Compare commits
2140 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ecde222512 | ||
|
26fcb1b2a0 | ||
|
e9c4e8123c | ||
|
a290e01bdf | ||
|
9cc392fa02 | ||
|
7c2046cce7 | ||
|
b13171cc45 | ||
|
9c645e2010 | ||
|
bb6f409e89 | ||
|
61ec7723f6 | ||
|
9c136a5579 | ||
|
a5733508ae | ||
|
c8e1e6dc8a | ||
|
30dcf6ff47 | ||
|
3473ebc0fe | ||
|
8c657910ae | ||
|
1886c44579 | ||
|
1dcc1871fb | ||
|
19e688effb | ||
|
6a2b885988 | ||
|
bfc4775b34 | ||
|
981004606b | ||
|
9d40fd1eda | ||
|
fbb6b56d99 | ||
|
f1f70133dc | ||
|
d0f55e5125 | ||
|
5e308dbd51 | ||
|
c3c554f4d6 | ||
|
320c06e0a4 | ||
|
b1484104bd | ||
|
c738a9a044 | ||
|
519cb71022 | ||
|
fcd92d27f7 | ||
|
3eacfa9831 | ||
|
1d64b614c7 | ||
|
a832dd7f67 | ||
|
a96b4d28e1 | ||
|
57e8b7f924 | ||
|
263eb856d5 | ||
|
5a4f088b24 | ||
|
c1913bfa7d | ||
|
474881e4c7 | ||
|
7e0aa822b6 | ||
|
940d780a4c | ||
|
ad9575ce18 | ||
|
ce86205df0 | ||
|
3cf9942465 | ||
|
153031482f | ||
|
1f74b1e2fd | ||
|
42393123a0 | ||
|
af2cff5177 | ||
|
5435b93df2 | ||
|
3a3dde6298 | ||
|
b4bc90fb85 | ||
|
02040cd25d | ||
|
bdc6bd4135 | ||
|
e720de401d | ||
|
ce97896ffd | ||
|
86fa4e9ee8 | ||
|
f09c166350 | ||
|
24868fdb2b | ||
|
a463250ecf | ||
|
d38e034e92 | ||
|
6eb9192cd1 | ||
|
94f15f1b3c | ||
|
ee296f36c1 | ||
|
598a7b3cc0 | ||
|
52baf26d7d | ||
|
fb3e6ee35c | ||
|
af1d1bd9c2 | ||
|
f32ad7699d | ||
|
79294bb6ca | ||
|
1cd4710718 | ||
|
48c19ade8e | ||
|
0acf70f836 | ||
|
fd584dd03b | ||
|
2740c68a63 | ||
|
62a242a894 | ||
|
8b060e9699 | ||
|
b1f769b671 | ||
|
77378da70a | ||
|
160030b75f | ||
|
0a0c3a2fb7 | ||
|
e9f1ca338f | ||
|
073c7e54df | ||
|
2834f2ccc2 | ||
|
6c56665403 | ||
|
0d794226ab | ||
|
ab2af11775 | ||
|
83662c9e50 | ||
|
6c1d52199f | ||
|
cfaf1ac67c | ||
|
a6caa0e680 | ||
|
c4b43f92ce | ||
|
3d1ccd9625 | ||
|
76bd53ef1f | ||
|
8fa209f0df | ||
|
88835512dd | ||
|
6b862dd9e9 | ||
|
be0b76c954 | ||
|
e45559da20 | ||
|
d7b5870ba6 | ||
|
df18c7cd59 | ||
|
2e74219ff9 | ||
|
b0ae954f1e | ||
|
a2404f104a | ||
|
38547ced7a | ||
|
9a9d9007cd | ||
|
bd2d81f691 | ||
|
1b9e7fbf2e | ||
|
d4a49d192f | ||
|
8cb66544d2 | ||
|
140ac192aa | ||
|
b961b13d60 | ||
|
febdb4a190 | ||
|
1d60b62e7a | ||
|
41e1e4cb68 | ||
|
d5b88e0df8 | ||
|
20fd61468d | ||
|
0a0d25dff4 | ||
|
38ba079baa | ||
|
33f7979359 | ||
|
8460b2544b | ||
|
bc514ea955 | ||
|
6f8893d950 | ||
|
de6aaf18ab | ||
|
0fe64cf5cc | ||
|
9a95531fb9 | ||
|
9df6a8dd06 | ||
|
1590a179fa | ||
|
5e16487ef6 | ||
|
2b3afbfef8 | ||
|
c3c7dcc9f5 | ||
|
273728b481 | ||
|
81a1057cac | ||
|
fd310c6445 | ||
|
a9b52518bf | ||
|
87da40068c | ||
|
b8f1eadb7f | ||
|
b522d8eaf6 | ||
|
89ff99322d | ||
|
56e17d1010 | ||
|
708067e875 | ||
|
d2ab0694b7 | ||
|
8a14a63d5d | ||
|
8235b18854 | ||
|
e0e9ebbe74 | ||
|
6e6259975e | ||
|
10bc8414b9 | ||
|
4e25e0dc5c | ||
|
b1a9793d94 | ||
|
6dea00668e | ||
|
ae9182c92e | ||
|
af17355fe7 | ||
|
dce3e50a00 | ||
|
cf31561267 | ||
|
a97f0b1298 | ||
|
d1e0f3ae18 | ||
|
47a6786e8f | ||
|
a69fcbb91e | ||
|
8e2b51b391 | ||
|
560af43204 | ||
|
9c119f919e | ||
|
baefec86f2 | ||
|
eb763d2dc2 | ||
|
512c650441 | ||
|
dc44fc9e27 | ||
|
05640f9a6b | ||
|
6f2fb57c08 | ||
|
2547cc4c8d | ||
|
112ddb3c77 | ||
|
9f4ef66f41 | ||
|
086f0790fc | ||
|
709b44f736 | ||
|
6cd4ff6d68 | ||
|
abd3e828de | ||
|
b85af50d14 | ||
|
0e8fd49669 | ||
|
945e22874e | ||
|
77ab47a984 | ||
|
ed8088f203 | ||
|
8831b22fc8 | ||
|
0341bd1758 | ||
|
9bb4a5fb25 | ||
|
ebfffea5dc | ||
|
81939ab265 | ||
|
f2fe84c9d3 | ||
|
051f463350 | ||
|
f626406685 | ||
|
dd971b6ee5 | ||
|
8776b822db | ||
|
fc76b1a6a3 | ||
|
9183200b6f | ||
|
f1b8abf503 | ||
|
9502356980 | ||
|
a535ca9db4 | ||
|
2c762899de | ||
|
24fd23493d | ||
|
6f1ed28d0a | ||
|
66b7d04b82 | ||
|
044afa838c | ||
|
7ba47f504c | ||
|
0be1717ff4 | ||
|
189a4e0078 | ||
|
3adf8785d8 | ||
|
b74862bfc5 | ||
|
01273124ea | ||
|
721ada7e16 | ||
|
bd9dc91396 | ||
|
de6c43a8d3 | ||
|
93dea7b942 | ||
|
f6fc6a5e56 | ||
|
ca24f7c143 | ||
|
17b0db6515 | ||
|
83b0600863 | ||
|
38961fb31b | ||
|
6c130b7960 | ||
|
7244d44a1d | ||
|
9b060aab34 | ||
|
ba5bbf3523 | ||
|
697b0295f3 | ||
|
66d7ebd6c3 | ||
|
ae24f1255f | ||
|
ec7e75a6e3 | ||
|
aee106ae69 | ||
|
2a881a90ac | ||
|
ce6c465942 | ||
|
3748a0ed33 | ||
|
7a1a2dec67 | ||
|
7ed1bbad49 | ||
|
078cc7660e | ||
|
af2893d2ce | ||
|
0fe5efba76 | ||
|
fb6631d317 | ||
|
cd0b8927c5 | ||
|
3fab34687c | ||
|
b2d78edae9 | ||
|
412cacac49 | ||
|
dcb9797f35 | ||
|
4dcee5cd84 | ||
|
a64211123f | ||
|
1645677c3a | ||
|
4f85ace525 | ||
|
e8fde702a0 | ||
|
e339f3852c | ||
|
032f94afc0 | ||
|
e9b50442fa | ||
|
77b3764481 | ||
|
90ccbef431 | ||
|
02ea9b9abc | ||
|
4cd598ae10 | ||
|
8eeb8ad779 | ||
|
2ffb103acb | ||
|
a0c17368ed | ||
|
d76e761d0b | ||
|
6023984703 | ||
|
cde7b53de3 | ||
|
b36a44a954 | ||
|
fcc3d5450d | ||
|
057cecb3e0 | ||
|
86c6e0e826 | ||
|
5c223b5f4e | ||
|
883aa30aca | ||
|
763b51fe22 | ||
|
dd1aa9163c | ||
|
e087797edc | ||
|
5e6f8489a9 | ||
|
48351fed79 | ||
|
875a5d309d | ||
|
70e876ee13 | ||
|
7a269e757e | ||
|
87edbeaf58 | ||
|
339f95b00c | ||
|
e480c761cd | ||
|
26c628f8a5 | ||
|
59d6907d71 | ||
|
b4450a3918 | ||
|
7032be6049 | ||
|
70a6a79b8c | ||
|
f24f77c5bd | ||
|
66ae79f9b8 | ||
|
378338c684 | ||
|
7da076df18 | ||
|
45fbadbb26 | ||
|
a7def771c8 | ||
|
543f1243e2 | ||
|
a001443ad7 | ||
|
36166c129a | ||
|
4e7a485e23 | ||
|
9e5795bf55 | ||
|
053b38e0bd | ||
|
2aa3a109a0 | ||
|
472708376d | ||
|
cfed3d59e9 | ||
|
95fd9d4863 | ||
|
c89bca6ec8 | ||
|
ee262c30c2 | ||
|
6b8240d4de | ||
|
4035c933df | ||
|
abd44dd284 | ||
|
95d7fe76b5 | ||
|
a052f397fe | ||
|
09d6e73b0a | ||
|
7fb6b71d52 | ||
|
07e37d7fc3 | ||
|
fbe3dc0dcd | ||
|
6018c0c2fc | ||
|
52a2f166fd | ||
|
26cb6a1929 | ||
|
7c63bbfe44 | ||
|
109026222e | ||
|
af8e629df4 | ||
|
f7f1daa69f | ||
|
01f980d49c | ||
|
99fab7e52a | ||
|
692292b1d4 | ||
|
cd608d9d5b | ||
|
ba67144e34 | ||
|
162d9d7d57 | ||
|
357f5a2cfd | ||
|
d1ca32b0a5 | ||
|
34f326c559 | ||
|
7785dac50e | ||
|
01f643e5eb | ||
|
8037f3e332 | ||
|
19e30b829a | ||
|
afe5176e01 | ||
|
a48317883d | ||
|
5ac92ae4eb | ||
|
8fb6ba19a1 | ||
|
314f7e7889 | ||
|
4fcf8fd23f | ||
|
10a30344e5 | ||
|
1206dda347 | ||
|
b764d17c64 | ||
|
ba0abdb88d | ||
|
1428b58dde | ||
|
e57425df5f | ||
|
5e7dfaf220 | ||
|
ad5c011b6c | ||
|
fcdd33b585 | ||
|
f767f066ad | ||
|
b8d0e5e5a1 | ||
|
26ad23f01e | ||
|
21d771e171 | ||
|
66616eb0f0 | ||
|
18eb8a2159 | ||
|
72a1fc3f64 | ||
|
96eea32a9d | ||
|
3239c7023a | ||
|
5333895a9f | ||
|
da05491992 | ||
|
b9f5d79f3d | ||
|
fddc515ee1 | ||
|
3d4516dc95 | ||
|
509c864cc3 | ||
|
8b22f435ad | ||
|
55d39595e1 | ||
|
f8944177a0 | ||
|
3060c4d887 | ||
|
13ee5dc728 | ||
|
06873fe69e | ||
|
a8ac212ee6 | ||
|
3d9d13222b | ||
|
745adabb05 | ||
|
3861b57dc6 | ||
|
99a4a80017 | ||
|
033ba26041 | ||
|
439999cb62 | ||
|
7291aa07ca | ||
|
9181e2652e | ||
|
409f76aa34 | ||
|
54e2c6181a | ||
|
a281d87315 | ||
|
2a5587f236 | ||
|
2d18b2d784 | ||
|
585f842206 | ||
|
8cb4304c13 | ||
|
737819b56e | ||
|
a7130e6530 | ||
|
f9cfed5aff | ||
|
f65a9dbfd2 | ||
|
96c59fada4 | ||
|
153a9d8ac7 | ||
|
297d4eec57 | ||
|
c31b4383e6 | ||
|
0375a3caa3 | ||
|
08cddba200 | ||
|
1bf43b0425 | ||
|
35828f9cea | ||
|
90af12fdb8 | ||
|
dc63182647 | ||
|
5fede23cf7 | ||
|
bc4762f270 | ||
|
01429d59bd | ||
|
731d15f9b5 | ||
|
f0bd7fae5c | ||
|
f8322cc2d4 | ||
|
dfdb9e393b | ||
|
bd07d7f32e | ||
|
f588c6f93c | ||
|
d9ec3d2c22 | ||
|
e2b87759d8 | ||
|
52e0aa11af | ||
|
1421c31179 | ||
|
d5587e32d0 | ||
|
28eb348707 | ||
|
91bcc18e6a | ||
|
5b43f13935 | ||
|
85b3fef08d | ||
|
cc7c48237c | ||
|
15037fa888 | ||
|
d595fef18f | ||
|
be5fa22b6f | ||
|
a5c6bbeee7 | ||
|
094a645e60 | ||
|
51acdfa633 | ||
|
2c16a75ef1 | ||
|
6fd7e0311c | ||
|
1bcf2dd0fc | ||
|
9a3cf949cf | ||
|
cec214f900 | ||
|
dad669d68b | ||
|
561f40d97e | ||
|
dad18dc5de | ||
|
5c95c4074b | ||
|
4301b9a12a | ||
|
0bbe0aed83 | ||
|
b16f797317 | ||
|
4bb71ae046 | ||
|
679b098aa7 | ||
|
e0e88fdb52 | ||
|
8bba3a257c | ||
|
8529c1287f | ||
|
9c7f7756b4 | ||
|
f1cfb16bf9 | ||
|
95796e1978 | ||
|
968b981ecb | ||
|
3aeb378b56 | ||
|
28bafe7427 | ||
|
1317b67657 | ||
|
3f462c771f | ||
|
31aa42c35e | ||
|
f7a17248b7 | ||
|
b60e6310bf | ||
|
6a89c6bf3b | ||
|
b3b7aae7d7 | ||
|
fe8c365d17 | ||
|
9acc3aac01 | ||
|
1ad23a065e | ||
|
de102fde5c | ||
|
77554fbd13 | ||
|
6863bff7c5 | ||
|
eaf6938c35 | ||
|
34ad2157dd | ||
|
0635309f23 | ||
|
2661ef53a2 | ||
|
eddca8f127 | ||
|
cef0211c00 | ||
|
86052540d9 | ||
|
930cb15e2c | ||
|
8bb9dd460b | ||
|
8a3c78ca0a | ||
|
62a5e36afd | ||
|
00b28f0aed | ||
|
7c94aa9f07 | ||
|
ec8c40b69b | ||
|
2981f3cbd1 | ||
|
c2e1819098 | ||
|
58f3ff69d8 | ||
|
72d8d10e64 | ||
|
63d02df0bc | ||
|
f579fd3895 | ||
|
34df34ba27 | ||
|
2689b37c35 | ||
|
9b6427144f | ||
|
9212eea8bd | ||
|
6de5d6dd0a | ||
|
08f08fea61 | ||
|
1ed2a8637f | ||
|
d8bcbdadd6 | ||
|
d196c13f2c | ||
|
7ba251d3a6 | ||
|
0b72c639fb | ||
|
bd1c5a42e8 | ||
|
845d8c0e63 | ||
|
bcb8a52418 | ||
|
322cb2387b | ||
|
bfe56942f9 | ||
|
b4c32e47c6 | ||
|
248d8680f7 | ||
|
1bda965a7c | ||
|
2ee305769d | ||
|
3a8a936575 | ||
|
6b6fbc4709 | ||
|
3fd2ffd466 | ||
|
b56ca2b834 | ||
|
10f77df8bb | ||
|
df7671d393 | ||
|
a263936243 | ||
|
11924d425b | ||
|
0bd5a5f382 | ||
|
757eb64be3 | ||
|
6b3aea933d | ||
|
2935275227 | ||
|
cbe045b946 | ||
|
c58a95ca2e | ||
|
80a3bce6d5 | ||
|
6f0289de49 | ||
|
0966d7660e | ||
|
27e90cc4e6 | ||
|
b785213c3a | ||
|
642a73508d | ||
|
8f7b023769 | ||
|
a122fb2900 | ||
|
a299a2cc5f | ||
|
47196d86ad | ||
|
a713cf7952 | ||
|
6cd7b8ff5e | ||
|
f8264f8277 | ||
|
0e4d5e9103 | ||
|
f599bcfef9 | ||
|
74a4e62cc9 | ||
|
63a414a544 | ||
|
7d1f5091a7 | ||
|
3b54cab3bc | ||
|
52d06d906e | ||
|
d9e949b27c | ||
|
b65fe9d64f | ||
|
168397e90d | ||
|
e3c1fcd2c6 | ||
|
a2bc86fbcb | ||
|
26c6446252 | ||
|
e5e44db5ac | ||
|
d4f833c739 | ||
|
806f44abe6 | ||
|
900bdc5ee2 | ||
|
200995bf29 | ||
|
3a90c1c192 | ||
|
cc68155dfa | ||
|
b8545eb1df | ||
|
76531da340 | ||
|
12bec1df68 | ||
|
2b778695b1 | ||
|
ad61852804 | ||
|
dbd8aee4ee | ||
|
677694b01a | ||
|
85f0241c0d | ||
|
ade2185a9f | ||
|
0d27005dda | ||
|
8ee2bdec4d | ||
|
de6ce276d0 | ||
|
fbea81dcd7 | ||
|
502c349b8b | ||
|
5fb0aa70de | ||
|
7750e1344c | ||
|
8be37130e9 | ||
|
fa055481a7 | ||
|
d080e5d7a8 | ||
|
ad07655630 | ||
|
7cceb8615a | ||
|
ab9c8f4859 | ||
|
ffb8a74111 | ||
|
45587194e5 | ||
|
ccbf391913 | ||
|
ebf0db4bbf | ||
|
7765efa6c4 | ||
|
02d4b6794c | ||
|
836b717346 | ||
|
9ac265980f | ||
|
40798da6b1 | ||
|
fc596e41d4 | ||
|
1f9b0f7cef | ||
|
7bcc15e416 | ||
|
1a3bdbaabf | ||
|
5e35fdbc52 | ||
|
ab2c486f25 | ||
|
7fd7430d38 | ||
|
089b98430f | ||
|
5c7fc05a32 | ||
|
ced0d3c2c0 | ||
|
1afc5d351d | ||
|
09bbc81470 | ||
|
f7274addcd | ||
|
09bfa2ef77 | ||
|
a48518d234 | ||
|
a4a9879643 | ||
|
d1ccd7a460 | ||
|
9181a4a1d8 | ||
|
3268e1611a | ||
|
ea9ec384c6 | ||
|
bbb958b7ed | ||
|
cf724176dc | ||
|
18d1c98f08 | ||
|
d0cd39a25f | ||
|
03d4fcd17d | ||
|
02d658be65 | ||
|
1e627c7e8f | ||
|
9170488b0a | ||
|
b02730a5ad | ||
|
9af26cbaac | ||
|
73741f1518 | ||
|
9a9cb61345 | ||
|
6abd6d8879 | ||
|
c3b51b4ceb | ||
|
321ea8a3a9 | ||
|
4d6263872d | ||
|
fcdd58ac94 | ||
|
ef8292d371 | ||
|
bc6a985f7c | ||
|
7320fc11d2 | ||
|
51f6d75db4 | ||
|
a328326e39 | ||
|
4eedf8a746 | ||
|
c5f5252145 | ||
|
3f189ae7fe | ||
|
7fadd469c9 | ||
|
823e874d20 | ||
|
739aaafa9a | ||
|
62d001225a | ||
|
e50947eb58 | ||
|
ca056d32d2 | ||
|
63a455f4f7 | ||
|
a0e0465036 | ||
|
d174a9d015 | ||
|
7eb6124721 | ||
|
f458780ba7 | ||
|
8ad52806de | ||
|
dc22a50dcc | ||
|
852341c601 | ||
|
d5ed6c1901 | ||
|
e15548cbf5 | ||
|
5e28e6b9ac | ||
|
c78d43f640 | ||
|
da41383476 | ||
|
6ff79835da | ||
|
1d608b204a | ||
|
c2b8bed3a8 | ||
|
3365ef7aaa | ||
|
68c17b26dc | ||
|
e647efd471 | ||
|
15db1ffdd5 | ||
|
4632b0f797 | ||
|
65c35a5530 | ||
|
c449a1c0e0 | ||
|
b020010f0d | ||
|
0276c72fe2 | ||
|
e4aec05d0f | ||
|
2919f852ad | ||
|
a6e3b9de37 | ||
|
04a9791be2 | ||
|
6b896a1c54 | ||
|
cb8df06685 | ||
|
bfe5506cc1 | ||
|
b64066fec7 | ||
|
ffd31d8330 | ||
|
d89254fedf | ||
|
a771ddf667 | ||
|
ce2e410468 | ||
|
c1982c04ff | ||
|
9a62026830 | ||
|
d12efccd0b | ||
|
54afffed19 | ||
|
fc8fcdbece | ||
|
abd1fedc9d | ||
|
9725985037 | ||
|
754f3359ec | ||
|
4c131b8c28 | ||
|
15c674ba29 | ||
|
00aff6a906 | ||
|
c45c3a72b5 | ||
|
662d450651 | ||
|
a8897becd2 | ||
|
d0126f4454 | ||
|
fdb64a5702 | ||
|
73a80ff7dc | ||
|
a795fd698d | ||
|
2fb0dc0a4a | ||
|
5b4653cf39 | ||
|
aa8e1497a3 | ||
|
eb13d846ef | ||
|
c674a175ee | ||
|
afabf30ec6 | ||
|
420158494d | ||
|
6b7b0e0eb3 | ||
|
ad70db7e0e | ||
|
ef1ce66793 | ||
|
c364fd80b6 | ||
|
3bc5d1bae0 | ||
|
e4e34acba1 | ||
|
ff3c36a7a2 | ||
|
1e7e3259b5 | ||
|
5e53f484be | ||
|
513bc32d87 | ||
|
e7c944ff0b | ||
|
9355a8ad0e | ||
|
a74e48a138 | ||
|
ea5ee7b0f9 | ||
|
bc8cf1b2d8 | ||
|
bb28d94884 | ||
|
a4f58b0a22 | ||
|
bcf8139708 | ||
|
9b0390c9da | ||
|
e88f58c34e | ||
|
8f402f5c77 | ||
|
60054da582 | ||
|
4626b8ced5 | ||
|
ab7d193f98 | ||
|
cbf84c1840 | ||
|
420fb69166 | ||
|
c9c28cb59a | ||
|
9073f34b30 | ||
|
fb5578c0d4 | ||
|
4244f716e0 | ||
|
07a4f970d4 | ||
|
2335097c99 | ||
|
bef0a2fef0 | ||
|
c48e6c91f5 | ||
|
f082b5ba54 | ||
|
8841bdd252 | ||
|
58261098fb | ||
|
9432d3035a | ||
|
9907fc2770 | ||
|
d42caa8672 | ||
|
8117ec8e20 | ||
|
ff2783f9fc | ||
|
156a51c945 | ||
|
c72ffae4a2 | ||
|
7f3b0030ea | ||
|
9a626948f8 | ||
|
5c43df66a8 | ||
|
d0e3c546f8 | ||
|
a9cb93d801 | ||
|
ee8f29d178 | ||
|
da363070c7 | ||
|
50cf891e01 | ||
|
715838cf89 | ||
|
cd0c3f9418 | ||
|
efaee2b68b | ||
|
372c699cc6 | ||
|
8cb01cdd29 | ||
|
7a243f890e | ||
|
10982a0f45 | ||
|
d4c378ed5d | ||
|
7872f68a45 | ||
|
ec8c848106 | ||
|
3b50ce8c54 | ||
|
afabb5957b | ||
|
1eeaa01234 | ||
|
e2898217d2 | ||
|
f81dadc5d0 | ||
|
a0019d86c5 | ||
|
3c4a9bba78 | ||
|
4348653431 | ||
|
09cfa9bb20 | ||
|
e7713a9028 | ||
|
906a1753be | ||
|
a3d519b671 | ||
|
8591f9d576 | ||
|
c10ec5548f | ||
|
684ac98c8e | ||
|
db89fa9881 | ||
|
9a80421d73 | ||
|
2ddacf40c0 | ||
|
92f4824884 | ||
|
9a2ffabc33 | ||
|
2977168da1 | ||
|
85e3f37503 | ||
|
ba015c1918 | ||
|
1556adb678 | ||
|
6bfe729112 | ||
|
c340668870 | ||
|
207422f83a | ||
|
004ba28378 | ||
|
6f38801ed8 | ||
|
1509eb7d82 | ||
|
b8d2bfc890 | ||
|
8a2ee95e4a | ||
|
bc91716082 | ||
|
a00034a6a7 | ||
|
8dc0dc4d69 | ||
|
2f4b7ce3dd | ||
|
d4f83cb1d4 | ||
|
aaab3306a8 | ||
|
2bafa2f2ac | ||
|
9ac378ae09 | ||
|
bf867bd9fd | ||
|
7fd9ff43af | ||
|
bebb569c43 | ||
|
74e33bb1a0 | ||
|
b591df55b0 | ||
|
bddf31443c | ||
|
b9e0e88fe9 | ||
|
5120d9ec33 | ||
|
0a423ffd40 | ||
|
505c9e8979 | ||
|
75deb02961 | ||
|
480211033d | ||
|
c0886cb5c6 | ||
|
294df8690c | ||
|
5374f652dd | ||
|
fb72ac9904 | ||
|
b6639d9e7e | ||
|
74cb79252c | ||
|
6cd3c93472 | ||
|
eb63e75379 | ||
|
ca9321624c | ||
|
40f18df90f | ||
|
0d63cfd6c3 | ||
|
3d6b22de6c | ||
|
fc233fcdd3 | ||
|
20370d4348 | ||
|
0f90671241 | ||
|
a866c4e388 | ||
|
e7241a989c | ||
|
6e788668f9 | ||
|
b246dba7e7 | ||
|
f98de3d5db | ||
|
fab7d60373 | ||
|
b4e5358145 | ||
|
486db1e797 | ||
|
78cb43d0dc | ||
|
870454330d | ||
|
509cfd15f2 | ||
|
2061daa902 | ||
|
629ca970a1 | ||
|
c8ad6f23a8 | ||
|
d8912fd0a7 | ||
|
925c80edd4 | ||
|
2f6afd375b | ||
|
d92646324c | ||
|
c9fe62a691 | ||
|
cb52ad3ba3 | ||
|
2ec4acfe52 | ||
|
1c64f1d0cf | ||
|
48f4f44289 | ||
|
80c19cbf7d | ||
|
c97cfde9f9 | ||
|
7b26b308ad | ||
|
4c10634d85 | ||
|
3ba7d7640f | ||
|
907995a221 | ||
|
7bf0985a57 | ||
|
3ca21d8c8a | ||
|
a3a87c8883 | ||
|
de4401823e | ||
|
3ee10f5983 | ||
|
0fc8ac8d4d | ||
|
41bb53a29f | ||
|
cdee6d55d3 | ||
|
e5a1afaa26 | ||
|
f50cbe74cb | ||
|
5dbbf91917 | ||
|
7424a29960 | ||
|
eb22ca2467 | ||
|
ddbcbe5458 | ||
|
6e54cfd2ac | ||
|
fc3d4b3def | ||
|
df55b2c516 | ||
|
4d9fb57e22 | ||
|
3ed08b5c39 | ||
|
d715471426 | ||
|
486a4929da | ||
|
aacddb745b | ||
|
924f499303 | ||
|
e863a200e8 | ||
|
bb7f8ae69d | ||
|
33b6fe72da | ||
|
733919be4a | ||
|
4333e5487b | ||
|
22ead933b6 | ||
|
d53a3af191 | ||
|
08e7b7e0ad | ||
|
68cb0782c0 | ||
|
0e5a8e0033 | ||
|
4945f33254 | ||
|
3fa05293fc | ||
|
27e5f2798d | ||
|
291ca0874a | ||
|
96f2aa1803 | ||
|
c6857501aa | ||
|
3aba1607b2 | ||
|
f667298b64 | ||
|
0f4c8d4923 | ||
|
6d2c5b2312 | ||
|
a95ce11ca6 | ||
|
808503d526 | ||
|
d4b6fb9214 | ||
|
9bce5a09f3 | ||
|
bd61f38169 | ||
|
cac9c63325 | ||
|
e6d555ac31 | ||
|
fd0dd9f54c | ||
|
88c161769d | ||
|
01bf1ae92d | ||
|
9193c71cff | ||
|
db278d81e4 | ||
|
bdad454a0d | ||
|
ac8064c754 | ||
|
736e963cef | ||
|
b191cd73a7 | ||
|
86d3ca48ae | ||
|
fd7e4f2268 | ||
|
e9475a9739 | ||
|
d4270e02e9 | ||
|
b9a263ecb2 | ||
|
4929d415a6 | ||
|
b9e1f518aa | ||
|
0caa44e979 | ||
|
ca56ca5bd8 | ||
|
a0f0dff88e | ||
|
e5cc38a210 | ||
|
6cb5bb7200 | ||
|
563696e291 | ||
|
c755b3c49e | ||
|
b9f3493dbc | ||
|
8c08e9e473 | ||
|
c2930b0ca5 | ||
|
4300759287 | ||
|
fc1854cadd | ||
|
933973b12c | ||
|
5b54b9cb11 | ||
|
d2f815bba7 | ||
|
a5a067d50f | ||
|
699e299345 | ||
|
05e114173d | ||
|
d958b3ff65 | ||
|
0d7e06a141 | ||
|
633095aee1 | ||
|
a4aeb9a1dd | ||
|
71005e1db3 | ||
|
d7d6d6f991 | ||
|
5986121cfc | ||
|
c452a4569e | ||
|
a182a208dc | ||
|
d273b4b48b | ||
|
afed7d4af0 | ||
|
b429e890ad | ||
|
2f976504e8 | ||
|
b5fc88227b | ||
|
4b7b859db9 | ||
|
f7d0de53bb | ||
|
603ec997ba | ||
|
f7266ef4c8 | ||
|
3d43e1568c | ||
|
3cf6a65da9 | ||
|
c1a3f003e8 | ||
|
3f61aea7fc | ||
|
bd68db51e0 | ||
|
b8a5ed710e | ||
|
34be601dd7 | ||
|
1d64ad1ccd | ||
|
dfb4ac0365 | ||
|
f2d7a3d26d | ||
|
6d415a7384 | ||
|
0ef8832b04 | ||
|
e42a037b7d | ||
|
fe18d69b65 | ||
|
a1a9a7fa9e | ||
|
07029f93e3 | ||
|
e99ef9c093 | ||
|
fef9ab674e | ||
|
ee37c37cab | ||
|
b636c1e1f8 | ||
|
8b9f0487c0 | ||
|
a6cbd5a2fd | ||
|
ece1667fb0 | ||
|
50bd8b4a09 | ||
|
93d91353a1 | ||
|
8dc9143b34 | ||
|
a0d9a1133c | ||
|
7740e4268c | ||
|
f36e4ba336 | ||
|
3df2ef8587 | ||
|
354309fcad | ||
|
e832bfc61e | ||
|
99057ed859 | ||
|
c47c5e466f | ||
|
edd00e8e70 | ||
|
82e7de2aaa | ||
|
b723714c0c | ||
|
a2903b6e63 | ||
|
9a1876571b | ||
|
c07d7165ab | ||
|
d695c5972f | ||
|
bbc09ed313 | ||
|
1d21b0da9a | ||
|
617a147706 | ||
|
d4dccfdb2d | ||
|
035e4bf727 | ||
|
9ec5bbd560 | ||
|
34482c5ed6 | ||
|
7d414b5628 | ||
|
d9528dfd09 | ||
|
12f5f8ba00 | ||
|
db0f3307e0 | ||
|
9c83825cb8 | ||
|
7a22471787 | ||
|
7548d9a8fe | ||
|
26789f9b36 | ||
|
b4524839bb | ||
|
6605c269cf | ||
|
c30478bf4a | ||
|
d986746ef9 | ||
|
a8fa061f2e | ||
|
72015b0226 | ||
|
f8e9726922 | ||
|
884363bd05 | ||
|
bdd240ecb6 | ||
|
04da292df9 | ||
|
85b8676b8e | ||
|
114bc13c23 | ||
|
5fef5f1ed4 | ||
|
807b60b0e6 | ||
|
fbc800e556 | ||
|
1991ee7a7d | ||
|
ffbfadbccf | ||
|
c3e2bce956 | ||
|
0c9520d7e3 | ||
|
1e7e5230cc | ||
|
f1efc97357 | ||
|
fb5ac6d6d7 | ||
|
4e7ca51beb | ||
|
d561600a31 | ||
|
024e843998 | ||
|
126f275e18 | ||
|
c65e5ff8e0 | ||
|
ef13e67572 | ||
|
7920fcbb5e | ||
|
fa36fdeb03 | ||
|
c143b5ccb4 | ||
|
05c8406fca | ||
|
69e3a45083 | ||
|
45259b6ec6 | ||
|
d6fe48112c | ||
|
dcf6e6b14d | ||
|
908697a963 | ||
|
bdaf961196 | ||
|
6bd5d9b1a4 | ||
|
beb0dae5a7 | ||
|
fad2d6b1d1 | ||
|
9cd830b6aa | ||
|
d9a16b0ff4 | ||
|
cb5c94ef5e | ||
|
85fbd66871 | ||
|
3da75d6125 | ||
|
d4a3a5c180 | ||
|
65e0fcbf10 | ||
|
e22aca49c8 | ||
|
71e3a473d6 | ||
|
c2cfc09f63 | ||
|
cbfad28f7e | ||
|
6a4a468022 | ||
|
01f10b56e8 | ||
|
90ec0a610e | ||
|
42bff1ce1b | ||
|
e3c7a1f31f | ||
|
0debbffa70 | ||
|
473b58d26d | ||
|
7e9498f04c | ||
|
300001e766 | ||
|
21fc6344bf | ||
|
a38edd891f | ||
|
794fa21137 | ||
|
977d1d1998 | ||
|
cde003bc98 | ||
|
9e4e1d1cb2 | ||
|
60142cd960 | ||
|
f9570a82cc | ||
|
36285ead57 | ||
|
13e488dace | ||
|
f169da8fd0 | ||
|
60741298b7 | ||
|
f73734acb0 | ||
|
fc360abe43 | ||
|
3996e11425 | ||
|
3a4fe3e391 | ||
|
98db002770 | ||
|
7c89b6934a | ||
|
380a19274d | ||
|
f1c1caf7bd | ||
|
e2997b8135 | ||
|
4ed6e4d016 | ||
|
ac8d24a1ce | ||
|
fc776921d5 | ||
|
55a653aca4 | ||
|
0d6a6b97f9 | ||
|
469ff45f01 | ||
|
bc077acfb8 | ||
|
4269626f5d | ||
|
8fa897aadb | ||
|
f549618d12 | ||
|
2fa47aaf31 | ||
|
b0874fb23a | ||
|
fb70fd77e8 | ||
|
01f17f9cbb | ||
|
4c853defb2 | ||
|
bd0db56ba0 | ||
|
95f0b3710d | ||
|
e0ac109dd1 | ||
|
86349527e7 | ||
|
18005ceee8 | ||
|
7653b3d088 | ||
|
911053f63f | ||
|
eb52f81a5c | ||
|
4839953328 | ||
|
aba0d93fda | ||
|
0de74c0448 | ||
|
ee927346b7 | ||
|
2f8015cbca | ||
|
f3bf7c4b38 | ||
|
e37c4d57da | ||
|
acff90c000 | ||
|
5f9e72dd71 | ||
|
be0bcb8f7d | ||
|
44c3d56439 | ||
|
519d731ddd | ||
|
119c00c22a | ||
|
12596dd697 | ||
|
cb38f5f0d7 | ||
|
b49384ffe4 | ||
|
7fb622638b | ||
|
bd0cc134bf | ||
|
476fd1f695 | ||
|
96053d13be | ||
|
c958bed418 | ||
|
2b2c240d39 | ||
|
1f0ae16216 | ||
|
b79392ba2c | ||
|
8ee98f0a4a | ||
|
82e78fb651 | ||
|
d0826b2c33 | ||
|
ff588200c0 | ||
|
5d6072524c | ||
|
07a66a70fc | ||
|
69ba8a3c2f | ||
|
a30c75ef71 | ||
|
d0b3727c5d | ||
|
6e94bf5b6d | ||
|
0f04e270a7 | ||
|
ec4f5007e7 | ||
|
21b906e0e0 | ||
|
7ebaf8e843 | ||
|
640398ced4 | ||
|
ebbe1fc236 | ||
|
aac8e45397 | ||
|
5ebfa5ecf7 | ||
|
12e041c9ef | ||
|
54913f06a3 | ||
|
44a36368a2 | ||
|
8f9ff930b3 | ||
|
e199f6db87 | ||
|
c83dd3ccd7 | ||
|
78fbafa1cd | ||
|
c0012540ed | ||
|
9ab6df0e54 | ||
|
685b775b68 | ||
|
9056a5a7b6 | ||
|
e1c56bcbfe | ||
|
15d68467a1 | ||
|
3b6ecc573e | ||
|
9427b1e594 | ||
|
3ca3eaa62c | ||
|
dda448e050 | ||
|
60873144ea | ||
|
a9d17c96be | ||
|
aaee895b2b | ||
|
7d7e17b351 | ||
|
c71a976e76 | ||
|
3623183072 | ||
|
e6bd979aeb | ||
|
266c160108 | ||
|
b5b6350cc7 | ||
|
bbcf4800de | ||
|
41056ace02 | ||
|
60a80dd678 | ||
|
0efda04920 | ||
|
8819e58882 | ||
|
28eeaf201b | ||
|
74bfcea6a8 | ||
|
16f1d7fad9 | ||
|
9aa38cf0ae | ||
|
a7fa7466fb | ||
|
3f73c61cee | ||
|
a64f4cd871 | ||
|
a41eff1276 | ||
|
b88fe572fe | ||
|
59ba6f8aec | ||
|
25343da6b7 | ||
|
60d17b97f5 | ||
|
8cb72d87e4 | ||
|
8872594ab9 | ||
|
b50584119b | ||
|
975f4f2a17 | ||
|
16e4f79f09 | ||
|
76cae20c33 | ||
|
b66f23cfd0 | ||
|
27d6e5d8cf | ||
|
ff5d5b97c3 | ||
|
ce46c4dec4 | ||
|
77e8be09a1 | ||
|
013d77488a | ||
|
29ad2496b6 | ||
|
97a013b2b7 | ||
|
77808223dc | ||
|
fc89851ce9 | ||
|
c4c6555814 | ||
|
df0087fb23 | ||
|
ef3c13fe2b | ||
|
0ad704e532 | ||
|
2220d2dab8 | ||
|
49f48e2aaa | ||
|
dce24df379 | ||
|
b59136c262 | ||
|
fb9664b636 | ||
|
5b736ae05e | ||
|
ee114b3075 | ||
|
123b16991b | ||
|
5792fc0bef | ||
|
42c93917ef | ||
|
8c0f860601 | ||
|
df30a4c0d1 | ||
|
9ce13f0035 | ||
|
3884b01503 | ||
|
a84c3adeab | ||
|
a65b784907 | ||
|
05dadad2e1 | ||
|
3a9b39b842 | ||
|
e612003293 | ||
|
a43577fa26 | ||
|
7e10dcdcf0 | ||
|
7ee1110351 | ||
|
51c4c51d9e | ||
|
fc4fe54099 | ||
|
b5b240d0be | ||
|
4c42f00a86 | ||
|
090fbd04af | ||
|
461de48625 | ||
|
9352ba6e4a | ||
|
5e883239f9 | ||
|
5ea08a2120 | ||
|
a6fa60868b | ||
|
99878ae7d6 | ||
|
26202014a2 | ||
|
f4f8b96788 | ||
|
e5ede16749 | ||
|
fbe3547129 | ||
|
23f7363c70 | ||
|
97c44042e1 | ||
|
a03caea549 | ||
|
aa23fb1d56 | ||
|
4f35aac6dd | ||
|
4418ca9e9f | ||
|
570611fc09 | ||
|
94dd5b1ebe | ||
|
74524e024d | ||
|
324e00194f | ||
|
e42b6dcc8e | ||
|
d71b799e75 | ||
|
87e7121332 | ||
|
94f6354c94 | ||
|
b79059ebdb | ||
|
07b7e8a1a6 | ||
|
7ae2fc37c0 | ||
|
4f98c1bebb | ||
|
2feec01e10 | ||
|
72b95e192e | ||
|
47aad254d8 | ||
|
bc14074d2a | ||
|
5ab5b1a190 | ||
|
b055f190f5 | ||
|
84b8953352 | ||
|
93a591d487 | ||
|
e6c0f38a7c | ||
|
d169305e5d | ||
|
f107ae4f9b | ||
|
bad7a08804 | ||
|
25cbf4cb35 | ||
|
7f179f9a58 | ||
|
5287ea8537 | ||
|
43e2aaebf0 | ||
|
e60eb66283 | ||
|
ca59b808d8 | ||
|
8a15fd44d5 | ||
|
dac2b8942e | ||
|
54a1c5b63a | ||
|
61b02bf6d3 | ||
|
9d048b2fdf | ||
|
d9e28a7422 | ||
|
1fecdf42ca | ||
|
d4bf85b67c | ||
|
7131ff27c3 | ||
|
a30f78c1c8 | ||
|
7e0afffca8 | ||
|
293c60fb9c | ||
|
f5be8b2a5e | ||
|
6772603c15 | ||
|
a22904f99b | ||
|
6710d2852f | ||
|
b157bc5cd7 | ||
|
10e1a03c76 | ||
|
d20df92e9f | ||
|
44170207ac | ||
|
9354799a26 | ||
|
33745be745 | ||
|
6a28070017 | ||
|
91b948332e | ||
|
d1a7fe2d44 | ||
|
8224ef20a4 | ||
|
a4c3464bc8 | ||
|
5966d76e9a | ||
|
c39324d11f | ||
|
8c151c62ce | ||
|
50d16d8215 | ||
|
3bbac9a5f2 | ||
|
3600fd277e | ||
|
e8bb4a7e36 | ||
|
36987cb1cc | ||
|
5382b4fa37 | ||
|
28ef8068c8 | ||
|
ca0cbd68d6 | ||
|
c281b47905 | ||
|
aca5064743 | ||
|
6f780316c4 | ||
|
4e262d81f0 | ||
|
6c2ff950ee | ||
|
7684069d0b | ||
|
73c85ae68a | ||
|
911e39ba09 | ||
|
9a421d510a | ||
|
3bc7172e5e | ||
|
1a83988e26 | ||
|
0d0fc2504a | ||
|
0d4402ee0c | ||
|
722def9362 | ||
|
6a8bef83b3 | ||
|
a9c3e2c7ba | ||
|
7fcb40739d | ||
|
5a3d319677 | ||
|
8466d0b681 | ||
|
5de179f1eb | ||
|
36e10595cc | ||
|
78c8723629 | ||
|
edd7f28104 | ||
|
dba1ab3fc0 | ||
|
3df9c48012 | ||
|
6f6450bcff | ||
|
1f34203167 | ||
|
fed20648c6 | ||
|
3fc3c5cae4 | ||
|
daa5366b57 | ||
|
ac1c299369 | ||
|
5bbb3ac49a | ||
|
014bdf911a | ||
|
874853fe18 | ||
|
274b71f8bc | ||
|
c41d543d81 | ||
|
7729ddab30 | ||
|
60c0e59a83 | ||
|
ac49e639bd | ||
|
f01b20c2af | ||
|
a0d47be088 | ||
|
521374e238 | ||
|
34806ee2c2 | ||
|
4a0d5138a1 | ||
|
e6a3758899 | ||
|
fcb7d9111e | ||
|
d907731027 | ||
|
ac8d295bb9 | ||
|
a963beb96e | ||
|
737b510116 | ||
|
47cba83450 | ||
|
21d4199a38 | ||
|
655c422c3c | ||
|
b6f8bd408f | ||
|
a3edd0b976 | ||
|
8e8efa5caf | ||
|
a41b8f62a2 | ||
|
452ee8c2df | ||
|
5ca6599ca9 | ||
|
dcedf6bfd0 | ||
|
1f4b43645b | ||
|
3d5140458b | ||
|
f16574085f | ||
|
3ed62d45f5 | ||
|
b1a7b0a186 | ||
|
ec0c68621c | ||
|
a0977af081 | ||
|
a3ef9efd2f | ||
|
d58f7c6ec9 | ||
|
d124c2c12e | ||
|
0229f70761 | ||
|
dde9281139 | ||
|
6eedfb572e | ||
|
edf81a232d | ||
|
c2cb92a0b0 | ||
|
640af300cb | ||
|
6c0c6182e9 | ||
|
05ad4445b5 | ||
|
1dd9f0747e | ||
|
150e01be8b | ||
|
95ee3216c4 | ||
|
3b5e409b38 | ||
|
eb201b614a | ||
|
162a6b8b5c | ||
|
4ec01769cb | ||
|
19b656132d | ||
|
6305c7e2ab | ||
|
04c60e8a1c | ||
|
b6ceb06a32 | ||
|
8cb2f85a08 | ||
|
7ccfb6ea88 | ||
|
531398b532 | ||
|
ec6ecf0d60 | ||
|
fdb0e31a78 | ||
|
01a9534729 | ||
|
921278c5ea | ||
|
d938f73207 | ||
|
344e63c2dc | ||
|
681144b2a3 | ||
|
e4295f5d3c | ||
|
77135ca3c7 | ||
|
29b548f07c | ||
|
cb33ef77f7 | ||
|
49ded54306 | ||
|
6c0a8a4337 | ||
|
e9a0ddf798 | ||
|
d217626318 | ||
|
4f5fcc2a37 | ||
|
ed94f4b1df | ||
|
a57b097afc | ||
|
eb42b894c4 | ||
|
af666e2209 | ||
|
2f2e746e56 | ||
|
b3e7619048 | ||
|
0121136498 | ||
|
7eb43a0b47 | ||
|
c0430a2248 | ||
|
6796b8bdad | ||
|
475d016029 | ||
|
201304e678 | ||
|
fdb104348c | ||
|
f54828352d | ||
|
cc157def63 | ||
|
8fc83655ab | ||
|
9fb549293a | ||
|
e4cc5b5b70 | ||
|
6f0b659b38 | ||
|
652bdf1518 | ||
|
f6ac0d73b4 | ||
|
ae47be0ce9 | ||
|
491c37eafe | ||
|
3ade7a8b0e | ||
|
3c7738b6d0 | ||
|
037318e2ff | ||
|
a9a499939e | ||
|
7e5bcd2ec3 | ||
|
f49ca48a22 | ||
|
9cb4e8bde8 | ||
|
95edb49bb8 | ||
|
fb69bf551e | ||
|
fe8d0f8ea8 | ||
|
acc5fa2a95 | ||
|
f2e33f8581 | ||
|
4748cdc2c9 | ||
|
2bc364023a | ||
|
3070f61e20 | ||
|
57df56dc62 | ||
|
e11ef5a7f0 | ||
|
6a17a3eeec | ||
|
66ff9a24c6 | ||
|
a3b3a7a34d | ||
|
c04b3559d0 | ||
|
e642b41b5b | ||
|
ba6881d685 | ||
|
20d8c9053b | ||
|
0749e4ed70 | ||
|
b0cc69ff80 | ||
|
02c4669e95 | ||
|
8550b76e23 | ||
|
fdf27e3d24 | ||
|
069023fca2 | ||
|
1fd6648db1 | ||
|
7a08c8b694 | ||
|
60aad3f19b | ||
|
51dcc2bc0f | ||
|
941525d1e0 | ||
|
5fb6c5b012 | ||
|
3affa73257 | ||
|
c647e27e15 | ||
|
f696ed48b3 | ||
|
73645f299a | ||
|
6aeb5f1172 | ||
|
ce8f07750f | ||
|
a32ad0dbf2 | ||
|
61ff12e8d4 | ||
|
02b0e96db8 | ||
|
e942440bb7 | ||
|
a27f1f17de | ||
|
e106ff0fef | ||
|
6f068e0b9c | ||
|
ada531c88a | ||
|
f0a2248c81 | ||
|
11f2524b9b | ||
|
b011e5f838 | ||
|
f45eb84d6b | ||
|
412c0a172d | ||
|
c1d8496b93 | ||
|
4657959790 | ||
|
2b0ba281a4 | ||
|
325a41c598 | ||
|
9b8efe1b27 | ||
|
024b741552 | ||
|
4e95f4678f | ||
|
a86b982591 | ||
|
ec8da00485 | ||
|
bcfe130d51 | ||
|
0e143f7275 | ||
|
7670b4e380 | ||
|
636a9123b8 | ||
|
caaee40889 | ||
|
1f130b6550 | ||
|
2ce47f49b1 | ||
|
0250e03b86 | ||
|
ce110aab90 | ||
|
fd92752f52 | ||
|
3c4a305976 | ||
|
791e5bbd55 | ||
|
46df6e7dd3 | ||
|
9ccf9d57a8 | ||
|
fa89bd830a | ||
|
3ba05d0274 | ||
|
0d9a8d70bf | ||
|
5c79184d3b | ||
|
3d619d9ccc | ||
|
afdf3ae7a1 | ||
|
943f7c06b5 | ||
|
27a9642090 | ||
|
d0b6ff2d08 | ||
|
97737ee9e3 | ||
|
5e27ccc37c | ||
|
682113892a | ||
|
376eb81181 | ||
|
4fc40d96d9 | ||
|
e6634531c7 | ||
|
66724826f5 | ||
|
04e375a523 | ||
|
65638973ea | ||
|
9c26bdd676 | ||
|
b31931c907 | ||
|
c74af2c21f | ||
|
c160b2e54b | ||
|
c4234f4542 | ||
|
62fa9c0f6e | ||
|
8198f06073 | ||
|
6f2117d786 | ||
|
b3ec3b487c | ||
|
d67957d015 | ||
|
94f131a0b7 | ||
|
7af0029175 | ||
|
f4228b04f8 | ||
|
ffaf243160 | ||
|
29d48bbd9a | ||
|
37dda79db2 | ||
|
063e3e85e1 | ||
|
42afaa9f66 | ||
|
366fcf76f6 | ||
|
72e8ec7d93 | ||
|
13a479a9f6 | ||
|
1194e48bd8 | ||
|
1e0666d1ef | ||
|
1c53ad6876 | ||
|
dc2a537f6b | ||
|
a5d3022e9f | ||
|
4541da1f17 | ||
|
a16cd9aef7 | ||
|
6cf446032f | ||
|
3fda2d9ac3 | ||
|
c03268707a | ||
|
7829e907c9 | ||
|
b5529e5138 | ||
|
d601afcebc | ||
|
892a90bf51 | ||
|
d52a8f08ed | ||
|
b7e27bf6b4 | ||
|
9ee96d6176 | ||
|
c0e1772e21 | ||
|
62dc160c65 | ||
|
f03303e5aa | ||
|
7bc2844b9d | ||
|
ba283755be | ||
|
2209beff8a | ||
|
00cc480bc1 | ||
|
d7de5b2afa | ||
|
221b72439b | ||
|
08e6f60941 | ||
|
10066209e7 | ||
|
08e95ed606 | ||
|
a5ad48aa18 | ||
|
81fdfcba22 | ||
|
24de6d6fc9 | ||
|
aec6fcd00b | ||
|
619082dbed | ||
|
09cdf5081c | ||
|
d7abbbfac4 | ||
|
c714196647 | ||
|
b702c1d9a8 | ||
|
56ac04c48e | ||
|
b58519b974 | ||
|
ad574f5e90 | ||
|
4941a657bf | ||
|
3d4bff9414 | ||
|
2d03616c10 | ||
|
fcb9ba08a8 | ||
|
77f4126f9b | ||
|
4c890ab202 | ||
|
d10e9b1b6e | ||
|
a6bee76581 | ||
|
2f4f5a6ad2 | ||
|
3853997295 | ||
|
76899c9ac5 | ||
|
99a5b3a98a | ||
|
219aff9a93 | ||
|
b6e1b3bff0 | ||
|
1ce888e828 | ||
|
1c10a801dc | ||
|
48fa83c9ac | ||
|
31ea3a2757 | ||
|
05e0003555 | ||
|
be79281418 | ||
|
01f53f6d6c | ||
|
107e0404de | ||
|
ab99e80333 | ||
|
3154a378a6 | ||
|
8e04f1c03e | ||
|
c0aadeab3d | ||
|
6c87698f1a | ||
|
db2e9f8bf3 | ||
|
9a4c5cef86 | ||
|
bdfc86f850 | ||
|
70dadfba28 | ||
|
01e1e34874 | ||
|
28a3cbfa87 | ||
|
0b480c2d3f | ||
|
391dea445a | ||
|
e074c72130 | ||
|
96f3f863e5 | ||
|
3877f6fd94 | ||
|
cbbc6df05a | ||
|
32ff7fb321 | ||
|
5537e57eec | ||
|
9c94af04cc | ||
|
3f0b15902d | ||
|
4d3835dde2 | ||
|
8514f42d0d | ||
|
6d9fbe8d41 | ||
|
849185d3c9 | ||
|
47cc757ed0 | ||
|
f6edd435af | ||
|
0c0dd914f7 | ||
|
c6405bc93b | ||
|
cdffdfbded | ||
|
0bbfb323b1 | ||
|
4f08359786 | ||
|
7efb17537a | ||
|
7e06769d44 | ||
|
5347ee4896 | ||
|
834bf30a10 | ||
|
22ea384ac8 | ||
|
3e6dd9ea9e | ||
|
10f363e9e7 | ||
|
69e8c014c3 | ||
|
dbb40e1dda | ||
|
d710b97276 | ||
|
0e6e8040ba | ||
|
c6fb0bad4b | ||
|
2d08217173 | ||
|
36645d9335 | ||
|
97d3aedba1 | ||
|
5976b20aec | ||
|
ad8573c739 | ||
|
7f9410fd34 | ||
|
71133f6b59 | ||
|
5d5d6c2c70 | ||
|
37fa462db5 | ||
|
1a2046a7eb | ||
|
3dff7e80fc | ||
|
6eea9239a7 | ||
|
75f1969bd2 | ||
|
e97755eb91 | ||
|
b938949cdb | ||
|
447af208b3 | ||
|
d47fbbbe96 | ||
|
767b72fbfa | ||
|
b94a8da9d6 | ||
|
12b5be239b | ||
|
0fbf72bb09 | ||
|
ae2117ff5a | ||
|
b80821c4b7 | ||
|
cf01b5a002 | ||
|
bb66d559e7 | ||
|
7b8fa3b922 | ||
|
777676b525 | ||
|
28f2a1309e | ||
|
4b0a7c2252 | ||
|
2625d9f7fe | ||
|
45f24c8a85 | ||
|
5f7c11f495 | ||
|
ec4d2d65a6 | ||
|
3e20f5dd3c | ||
|
7014b5a150 | ||
|
f8427ab789 | ||
|
31fc2bfeb7 | ||
|
fb5bc16c83 | ||
|
724075e448 | ||
|
45cb9a2e80 | ||
|
456eee05f2 | ||
|
23872f77a8 | ||
|
37c1999965 | ||
|
86dd4dd784 | ||
|
00b65abd09 | ||
|
fee55fa642 | ||
|
76ea1962be | ||
|
df3cf72d29 | ||
|
32dd594f06 | ||
|
ba0ba1de94 | ||
|
660e71f032 | ||
|
169e6fdba4 | ||
|
138aeaf8c7 | ||
|
33669793b7 | ||
|
80f4bf9475 | ||
|
bed869b08e | ||
|
f2150ee7e1 | ||
|
eaf89995ee | ||
|
2311b42bca | ||
|
a4fbccac9b | ||
|
a0cf93a7ca | ||
|
f444c7d4a5 | ||
|
8ef4c12f97 | ||
|
c520c55ff4 | ||
|
6145748bfb | ||
|
1a1026b367 | ||
|
8c45bd32b7 | ||
|
2b5cee05e6 | ||
|
5442954db6 | ||
|
5ee382c8eb | ||
|
901cb44f5e | ||
|
7388461ede | ||
|
5223627b71 | ||
|
646c4a3ccc | ||
|
0b9e78df2c | ||
|
a9c24b456d | ||
|
b4463bf42c | ||
|
8f8dc66c70 | ||
|
b746250e71 | ||
|
26b7e7ec8e | ||
|
bc09760c84 | ||
|
ceb229c6ac | ||
|
1e6ac33ef1 | ||
|
86eafe7a33 | ||
|
00f46dc149 | ||
|
396c7ab9ee | ||
|
fa2cef6395 | ||
|
04638c9065 | ||
|
02bb5b6742 | ||
|
fad5fafa32 | ||
|
b0dd231018 | ||
|
0b5f005a5d | ||
|
babca8d47b | ||
|
eb462955fe | ||
|
b79db36336 | ||
|
404ea0ce6d | ||
|
d3971b26e4 | ||
|
a44a201f00 | ||
|
1d80fdddd4 | ||
|
f09745b4ad | ||
|
d13ae0610e | ||
|
3eaa447323 | ||
|
604506da10 | ||
|
122ce11381 | ||
|
8cbd9f7f08 | ||
|
7c41e5bafc | ||
|
4452f784a8 | ||
|
ced0ae0d65 | ||
|
876c51302a | ||
|
a6877e7c13 | ||
|
f633d1fa5b | ||
|
4f90b41343 | ||
|
e4ddf8bc33 | ||
|
613ab9febc | ||
|
e92cceecc1 | ||
|
3283f3ed7d | ||
|
0ed30b802d | ||
|
beefff8cce | ||
|
b1554d6a89 | ||
|
4230b03884 | ||
|
2182b8339e | ||
|
b07b77c58f | ||
|
6542407fa3 | ||
|
ebf995536b | ||
|
adcd7f10ee | ||
|
af83936047 | ||
|
c3b5b97a41 | ||
|
6c58ea18dc | ||
|
830b287e5d | ||
|
52549d51ab | ||
|
fe05ed13e5 | ||
|
3a46e7fc0a | ||
|
88674e21cf | ||
|
a0673c7028 | ||
|
592af80659 | ||
|
3ec9b3b021 | ||
|
ca2d3a192c | ||
|
209bf7d746 | ||
|
13777cc1aa | ||
|
bffc77e478 | ||
|
0ebb7eecdb | ||
|
99863bb799 | ||
|
800d2f0859 | ||
|
f397844603 | ||
|
2d895f328c | ||
|
b14b182084 | ||
|
8687d25d88 | ||
|
7001edcd1d | ||
|
4a1e88f4bf | ||
|
b41608d40b | ||
|
c5d45edf2d | ||
|
0116b6341c | ||
|
3e7ecda80f | ||
|
f0e5b2b6f9 | ||
|
5976ec9323 | ||
|
eb3463fad1 | ||
|
5f9e5869e9 | ||
|
950480bb77 | ||
|
6530ec58c7 | ||
|
b1515c5e3f | ||
|
6581f119fd | ||
|
9ad7c12710 | ||
|
8e289215b4 | ||
|
3718c3be56 | ||
|
c3c051385c | ||
|
21c688a8a8 | ||
|
668b883651 | ||
|
c396aeed52 | ||
|
40f541bc31 | ||
|
44974f98a0 | ||
|
b7cb3df9bc | ||
|
432e6d5395 | ||
|
fdf805bc7b | ||
|
73e13f3875 | ||
|
da959e1296 | ||
|
94600c54cb | ||
|
c4fc2e089d | ||
|
06444c1c27 | ||
|
f8897942f3 | ||
|
4d0b4cfb36 | ||
|
7116634739 | ||
|
36492f4857 | ||
|
3a887af513 | ||
|
3142992c57 | ||
|
68a9b88b58 | ||
|
3c801e5b91 | ||
|
ecd46f8560 | ||
|
dee8ce587d | ||
|
4c24186911 | ||
|
af360a1a20 | ||
|
b5406240c6 | ||
|
73bfbba5f7 | ||
|
46d7bfecdb | ||
|
a734927591 | ||
|
255706e173 | ||
|
b2fbf46e60 | ||
|
e37495d80b | ||
|
beb6b950f7 | ||
|
2d1c0be24e | ||
|
9941651b3c | ||
|
31fda124f3 | ||
|
b7f6498a5c | ||
|
282da1c2b6 | ||
|
8e6ec6ef0c | ||
|
704b3ee673 | ||
|
c18a1c3eca | ||
|
4e1870197e | ||
|
3bf61cce95 | ||
|
68889b0544 | ||
|
8a90a47fc2 | ||
|
c93c4cc5e6 | ||
|
06cba7defd | ||
|
8b76bbe51d | ||
|
aa1d3a4c2e | ||
|
66817411f9 | ||
|
23c3196935 | ||
|
38e73a188a | ||
|
3fdf588cc9 | ||
|
9412fe8a0a | ||
|
c6450e60e1 | ||
|
8126e9f4b1 | ||
|
70e4104c17 | ||
|
29e0e1760b | ||
|
442b7b4c4d | ||
|
548153fd5e | ||
|
5060ed8970 | ||
|
d18e064d21 | ||
|
0cfb3c7ab4 | ||
|
2e0c2f2e77 | ||
|
48f9a61ff0 | ||
|
0042e3ae02 | ||
|
a1204cf246 | ||
|
fc499d9e7c | ||
|
b83704dac2 | ||
|
b93e46de14 | ||
|
3c49aa9d9d | ||
|
a448b48eaf | ||
|
3c6551f202 | ||
|
9e0c7ed29a | ||
|
677293f3a9 | ||
|
34bd7ce3a7 | ||
|
21a07e7419 | ||
|
6b50ea6504 | ||
|
895647b908 | ||
|
0ece58b9cb | ||
|
49a56cf131 | ||
|
5fa0d798e2 | ||
|
cadc506aa5 | ||
|
eee0ccef8c | ||
|
088bd632ab | ||
|
52b5d7143b | ||
|
60bf14d4dd | ||
|
c00fb44cee | ||
|
5111880edf | ||
|
3d78b44a8e | ||
|
f2d71d41a8 | ||
|
b75b290351 | ||
|
701ae06e4a | ||
|
edd0b809b7 | ||
|
98a0d17431 | ||
|
b1bd56cd51 | ||
|
ae336da7a1 | ||
|
4a61b80dd6 | ||
|
ef99fe2d18 | ||
|
352ebc3193 | ||
|
556799428c | ||
|
0b077b9601 | ||
|
80bec9c5cf | ||
|
c24685c49a | ||
|
2b99fa81f3 | ||
|
e87443b3e4 | ||
|
74ea597bd8 | ||
|
354a42dd00 | ||
|
4cedca3427 | ||
|
e99be28a73 | ||
|
32389e4ab8 | ||
|
01d7fc0ac9 | ||
|
d74c8261aa | ||
|
ac373545d0 | ||
|
a21948d2c6 | ||
|
940480effe | ||
|
29c593b8b0 | ||
|
0c444e6f2b | ||
|
6cf6e16d22 | ||
|
abef758ff6 | ||
|
e5f9663a0e | ||
|
ff5ed561cc | ||
|
6b76270889 | ||
|
5d040f45c8 | ||
|
cebdcc71a7 | ||
|
eec14be10d | ||
|
c179936b54 | ||
|
649a565801 | ||
|
2d4ebf5eb5 | ||
|
754beed3a1 | ||
|
df5059944b | ||
|
9f0927351d | ||
|
736edf44e4 | ||
|
8ecf8eb76c | ||
|
3cd1a5b1d5 | ||
|
39507b9d0d | ||
|
dfcf9d133e | ||
|
8a74942da7 | ||
|
2fe42138c7 | ||
|
1563146918 | ||
|
cf3aea8075 | ||
|
a539dc41f3 | ||
|
6cea480210 | ||
|
3b4bb48a0f | ||
|
206717828b | ||
|
316d26ede2 | ||
|
71fd32b1f4 | ||
|
f2e471707e | ||
|
fcf3b4e4e2 | ||
|
1e735c26c4 | ||
|
7c5df5dfe3 | ||
|
5b62f91bb4 | ||
|
e8b8fb0835 | ||
|
6663ced38d | ||
|
0b03264fb0 | ||
|
c99a8a9b15 | ||
|
ea0fb15ff2 | ||
|
05a59b17be | ||
|
8b18fdd322 | ||
|
1349f584be | ||
|
48db85187e | ||
|
d1e054d713 | ||
|
ce578534fe | ||
|
c7c4a5c602 | ||
|
3f40a95929 | ||
|
5c25c42da8 | ||
|
96011bc2ae | ||
|
4f59577fd1 | ||
|
494fcd60ab | ||
|
544919175c | ||
|
ede8f4714f | ||
|
b512496818 | ||
|
8094f7234c | ||
|
7dfd9f0378 | ||
|
bc51f88805 | ||
|
e04e2537a8 | ||
|
af982a02af | ||
|
03277899ca | ||
|
6756843be7 | ||
|
ac35417ab0 | ||
|
092c951078 | ||
|
9ba38e668a | ||
|
f665899116 | ||
|
de464e17cc | ||
|
0eed56380d | ||
|
487c26db44 | ||
|
0a57b43f09 | ||
|
48f8d7ed0f | ||
|
d77399727c | ||
|
56ea07c1ec | ||
|
414ef54cfe | ||
|
0a0f00da3b | ||
|
bee109c784 | ||
|
5d608a2db5 | ||
|
7c6ef0cfd0 | ||
|
0cf859344a | ||
|
6125b2520b | ||
|
bd5ed2bcf0 | ||
|
a2a58f7b39 | ||
|
87980c6df8 | ||
|
f9a2ca5c32 | ||
|
665dfdfe8e | ||
|
2b0bee085b | ||
|
ddfefb291d | ||
|
5d842a7533 | ||
|
2284a27814 | ||
|
f68cf10efa | ||
|
89e3c25a90 | ||
|
6b1f14647c | ||
|
14ee4850af | ||
|
cc62d984d2 | ||
|
534dbc9b6e | ||
|
8ad116fe7b | ||
|
ca5e34a9a9 | ||
|
9ff1129510 | ||
|
4b1dd8a2a5 | ||
|
b5bdfe27be | ||
|
0ef0b0b661 | ||
|
802638ce8b | ||
|
cfd6e0d65d | ||
|
93664aeb4e | ||
|
6f9d2d0567 | ||
|
d2b6947886 | ||
|
bc3224e0b9 | ||
|
ba75c4c62c | ||
|
3fc1817e7a | ||
|
ab1352b48e | ||
|
89b88a2d5d | ||
|
d37db4304c | ||
|
a6b18feed9 | ||
|
987e4e02a9 | ||
|
d646612a25 | ||
|
8ffa5e9357 | ||
|
d92b3fda91 | ||
|
b757e7a769 | ||
|
26dcbfc1f9 | ||
|
94f7363b8f | ||
|
a6313c9e9e | ||
|
3cdce17d28 | ||
|
184d1bd046 | ||
|
c88982d0d5 | ||
|
57282cfe16 | ||
|
263d9a222a | ||
|
73bbfc27d0 | ||
|
4027139d9c | ||
|
d215fa9ade | ||
|
b261e046bb | ||
|
4bca6fdfc4 | ||
|
9c1eca23ae | ||
|
66953319c4 | ||
|
dfc317124c | ||
|
debb5aeed6 | ||
|
f724a3a61a | ||
|
f5e573371c | ||
|
86192a6950 | ||
|
ed75f11f3e | ||
|
dcccb2ee2b | ||
|
412a190b42 | ||
|
d2b260fc1e | ||
|
723c2d47bb | ||
|
22d0e82d92 | ||
|
cb91b8f5fa | ||
|
a230df0032 | ||
|
b391afef49 | ||
|
5441591409 | ||
|
7cf5320f50 | ||
|
04c31f3d06 | ||
|
e5652be2a9 | ||
|
d068593582 | ||
|
3e0daa7e3c | ||
|
d8034f4156 | ||
|
2b5030e629 | ||
|
f453d407a9 | ||
|
49a40115c8 | ||
|
f7f2895eec | ||
|
0c3409a028 | ||
|
f896d1a5bc | ||
|
3b5f40c1f7 | ||
|
e74bb78a96 | ||
|
99c9f792f2 | ||
|
0a5c3d021a | ||
|
b9a5ca60b2 | ||
|
861673594d | ||
|
3651ee5480 | ||
|
7a82d1ff17 | ||
|
9421366e4f | ||
|
b806a36cfc | ||
|
2193d6a81f | ||
|
9ee2f006ac | ||
|
c34cc1608b | ||
|
1eb7f879f0 | ||
|
6c4f4f49bd | ||
|
831322b8b2 | ||
|
573c1ef94f | ||
|
a2cddda590 | ||
|
3b9f7031d5 | ||
|
9892d06c0d | ||
|
d1e475da89 | ||
|
c45dc277b6 |
38
.editorconfig
Normal file
38
.editorconfig
Normal file
@@ -0,0 +1,38 @@
|
||||
# EditorConfig is awesome: http://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = tab
|
||||
tab_width = 2
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# Matches multiple files with brace expansion notation
|
||||
# Set default charset
|
||||
[*.{js,py}]
|
||||
charset = utf-8
|
||||
|
||||
# 4 space indentation
|
||||
[*.py]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
# Tab indentation (no size specified)
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
||||
# Indentation override for all JS under lib directory
|
||||
[scripts/**.js]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# Matches the exact files either package.json or .travis.yml
|
||||
[{package.json,.travis.yml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
38
.gitattributes
vendored
Normal file
38
.gitattributes
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
# FROM https://github.com/libgit2/libgit2sharp
|
||||
# Text files that should be normalized to LF in odb.
|
||||
*.cs text diff=csharp
|
||||
*.config text
|
||||
|
||||
*.sln text
|
||||
*.csproj text
|
||||
|
||||
*.md text
|
||||
*.sh text
|
||||
*.ps1 text
|
||||
*.cmd text
|
||||
*.bat text
|
||||
*.markdown text
|
||||
*.msbuild text
|
||||
|
||||
Lib/* binary
|
||||
GitHub.Tests.Integration/Resources/* binary
|
||||
|
||||
|
||||
# Binary files that should not be normalized or diffed
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.gif binary
|
||||
|
||||
*.pfx binary
|
||||
*.snk binary
|
||||
*.dll binary
|
||||
*.exe binary
|
||||
*.lib binary
|
||||
*.exp binary
|
||||
*.pdb binary
|
||||
*.sdf binary
|
||||
*.7z binary
|
||||
|
||||
|
||||
# Catch all for anything we forgot. Add rules if you get CRLF -> LF warnings.
|
||||
* text eol=lf
|
33
.github/ISSUE_TEMPLATE.md
vendored
Normal file
33
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
**In raising this issue, I confirm the following (please check boxes, eg [X]) Failure to fill the template will close your issue:**
|
||||
|
||||
- [] I have read and understood the [contributors guide](https://github.com/pi-hole/pi-hole/blob/master/CONTRIBUTING.md).
|
||||
- [] The issue I am reporting can be *replicated*
|
||||
- [] The issue I am reporting isn't a duplicate (see [FAQs](https://github.com/pi-hole/pi-hole/wiki/FAQs), [closed issues](https://github.com/pi-hole/pi-hole/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), and [open issues](https://github.com/pi-hole/pi-hole/issues)).
|
||||
|
||||
**How familiar are you with the codebase?:**
|
||||
|
||||
_{replace this text with a number from 1 to 10, with 1 being not familiar, and 10 being very familiar}_
|
||||
|
||||
---
|
||||
**[BUG REPORT | OTHER]:**
|
||||
|
||||
Please [submit your feature request here](https://discourse.pi-hole.net/c/feature-requests), so it is votable by the community. It's also easier for us to track.
|
||||
|
||||
**[BUG | ISSUE] Expected Behaviour:**
|
||||
|
||||
|
||||
**[BUG | ISSUE] Actual Behaviour:**
|
||||
|
||||
|
||||
**[BUG | ISSUE] Steps to reproduce:**
|
||||
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
|
||||
**(Optional) Debug token generated by `pihole -d`:**
|
||||
|
||||
`<token>`
|
||||
|
||||
_This template was created based on the work of [`udemy-dl`](https://github.com/nishad/udemy-dl/blob/master/LICENSE)._
|
19
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
19
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
**By submitting this pull request, I confirm the following (please check boxes, eg [X]) _Failure to fill the template will close your PR_:**
|
||||
|
||||
***Please submit all pull requests against the `development` branch. Failure to do so will delay or deny your request***
|
||||
|
||||
- [] I have read and understood the [contributors guide](https://github.com/pi-hole/pi-hole/blob/master/CONTRIBUTING.md).
|
||||
- [] I have checked that [another pull request](https://github.com/pi-hole/pi-hole/pulls) for this purpose does not exist.
|
||||
- [] I have considered, and confirmed that this submission will be valuable to others.
|
||||
- [] I accept that this submission may not be used, and the pull request closed at the will of the maintainer.
|
||||
- [] I give this submission freely, and claim no ownership to its content.
|
||||
|
||||
**How familiar are you with the codebase?:**
|
||||
|
||||
_{replace this text with a number from 1 to 10, with 1 being not familiar, and 10 being very familiar}_
|
||||
|
||||
---
|
||||
_{replace this line with your pull request content}_
|
||||
|
||||
|
||||
_This template was created based on the work of [`udemy-dl`](https://github.com/nishad/udemy-dl/blob/master/LICENSE)._
|
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
.DS_Store
|
||||
*.pyc
|
||||
*.swp
|
||||
__pycache__
|
||||
.cache
|
||||
.pullapprove.yml
|
25
.idea/codeStyleSettings.xml
generated
Normal file
25
.idea/codeStyleSettings.xml
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectCodeStyleSettingsManager">
|
||||
<option name="PER_PROJECT_SETTINGS">
|
||||
<value>
|
||||
<option name="OTHER_INDENT_OPTIONS">
|
||||
<value>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="8" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
<option name="USE_TAB_CHARACTER" value="false" />
|
||||
<option name="SMART_TABS" value="false" />
|
||||
<option name="LABEL_INDENT_SIZE" value="0" />
|
||||
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
|
||||
<option name="USE_RELATIVE_INDENTS" value="false" />
|
||||
</value>
|
||||
</option>
|
||||
<MarkdownNavigatorCodeStyleSettings>
|
||||
<option name="RIGHT_MARGIN" value="72" />
|
||||
</MarkdownNavigatorCodeStyleSettings>
|
||||
</value>
|
||||
</option>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</component>
|
||||
</project>
|
38
.pullapprove.yml
Normal file
38
.pullapprove.yml
Normal file
@@ -0,0 +1,38 @@
|
||||
version: 2
|
||||
|
||||
always_pending:
|
||||
title_regex: '(WIP|wip)'
|
||||
labels:
|
||||
- wip
|
||||
explanation: 'This PR is a work in progress...'
|
||||
|
||||
group_defaults:
|
||||
reset_on_push:
|
||||
enabled: true
|
||||
reject_value: -2
|
||||
approve_regex: '^(Approved|:shipit:|:\+1:|Engage|:taco:)'
|
||||
reject_regex: '^(Rejected|:-1:|Borg)'
|
||||
author_approval:
|
||||
auto: true
|
||||
|
||||
|
||||
groups:
|
||||
development:
|
||||
approve_by_comment:
|
||||
enabled: true
|
||||
conditions:
|
||||
branches:
|
||||
- development
|
||||
required: 2
|
||||
teams:
|
||||
- approvers
|
||||
|
||||
master:
|
||||
approve_by_comment:
|
||||
enabled: true
|
||||
conditions:
|
||||
branches:
|
||||
- master
|
||||
required: 4
|
||||
teams:
|
||||
- approvers
|
10
.travis.yml
Normal file
10
.travis.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
sudo: required
|
||||
services:
|
||||
- docker
|
||||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
install:
|
||||
- pip install -r requirements.txt
|
||||
|
||||
script: py.test -vv
|
39
CONTRIBUTING.md
Normal file
39
CONTRIBUTING.md
Normal file
@@ -0,0 +1,39 @@
|
||||
_This template was created based on the work of [`udemy-dl`](https://github.com/nishad/udemy-dl/blob/master/LICENSE)._
|
||||
|
||||
# Contributors Guide
|
||||
|
||||
Please read and understand the contribution guide before creating an issue or pull request.
|
||||
|
||||
## Etiquette
|
||||
|
||||
- Our goal for Pi-hole is **stability before features**. This means we focus on squashing critical bugs before adding new features. Often, we can do both in tandem, but bugs will take priority over a new feature.
|
||||
- Pi-hole is open source and [powered by donations](https://pi-hole.net/donate/), and as such, we give our **free time** to build, maintain, and **provide user support** for this project. It would be extremely unfair for us to suffer abuse or anger for our hard work, so please take a moment to consider that.
|
||||
- Please be considerate towards the developers and other users when raising issues or presenting pull requests.
|
||||
- Respect our decision(s), and do not be upset or abusive if your submission is not used.
|
||||
|
||||
## Viability
|
||||
|
||||
When requesting or submitting new features, first consider whether it might be useful to others. Open source projects are used by many people, who may have entirely different needs to your own. Think about whether or not your feature is likely to be used by other users of the project.
|
||||
|
||||
## Procedure
|
||||
|
||||
**Before filing an issue:**
|
||||
|
||||
- Attempt to replicate and **document** the problem, to ensure that it wasn't a coincidental incident.
|
||||
- Check to make sure your feature suggestion isn't already present within the project.
|
||||
- Check the pull requests tab to ensure that the bug doesn't have a fix in progress.
|
||||
- Check the pull requests tab to ensure that the feature isn't already in progress.
|
||||
|
||||
**Before submitting a pull request:**
|
||||
|
||||
- Check the codebase to ensure that your feature doesn't already exist.
|
||||
- Check the pull requests to ensure that another person hasn't already submitted the feature or fix.
|
||||
|
||||
## Technical Requirements
|
||||
|
||||
- Submit Pull Requests to the **development branch only**.
|
||||
- Before Submitting your Pull Request, merge `development` with your new branch and fix any conflicts. (Make sure you don't break anything in development!)
|
||||
- Please use the [Google Style Guide for Shell](https://google.github.io/styleguide/shell.xml) for your code submission styles.
|
||||
- Commit Unix line endings.
|
||||
- Please use the Pi-hole brand: **Pi-hole** (Take a special look at the capitalized 'P' and a low 'h' with a hyphen)
|
||||
- (Optional fun) keep to the theme of Star Trek/black holes/gravity.
|
389
LICENSE
389
LICENSE
@@ -1,339 +1,146 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
Copyright (C) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||
Pi-hole Core
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
This software is licensed under the European Union Public License (EUPL)
|
||||
The license is available in the 22 official languages of the EU. The English version is included here.
|
||||
Please see https://joinup.ec.europa.eu/community/eupl/og_page/eupl for official translations of the other languages.
|
||||
|
||||
Preamble
|
||||
This license applies to the whole project EXCEPT:
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
- any commits made to the master branch prior to the release of version 3.0
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
The licenses that existed prior to this change have remained intact.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
-------------------------------------------------------------
|
||||
EUROPEAN UNION PUBLIC LICENCE v. 1.2
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
EUPL © the European Union 2007, 2016
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
This European Union Public Licence (the EUPL) applies to the Work (as defined below) which is provided under the terms of this Licence. Any use of the Work, other than as authorised under this Licence is prohibited (to the extent such use is covered by a right of the copyright holder of the Work).
|
||||
The Work is provided under the terms of this Licence when the Licensor (as defined below) has placed the following notice immediately following the copyright notice for the Work:
|
||||
Licensed under the EUPL
|
||||
or has expressed by any other means his willingness to license under the EUPL.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
1. Definitions
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
In this Licence, the following terms have the following meaning:
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
- The Licence: this Licence.
|
||||
- The Original Work: the work or software distributed or communicated by the Licensor under this Licence, available as Source Code and also as Executable Code as the case may be.
|
||||
- Derivative Works: the works or software that could be created by the Licensee, based upon the Original Work or modifications thereof. This Licence does not define the extent of modification or dependence on the Original Work required in order to classify a work as a Derivative Work; this extent is determined by copyright law applicable in the country mentioned in Article 15.
|
||||
- The Work: the Original Work or its Derivative Works.
|
||||
- The Source Code: the human-readable form of the Work which is the most convenient for people to study and modify.
|
||||
- The Executable Code: any code which has generally been compiled and which is meant to be interpreted by a computer as a program.
|
||||
- The Licensor: the natural or legal person that distributes or communicates the Work under the Licence.
|
||||
- Contributor(s): any natural or legal person who modifies the Work under the Licence, or otherwise contributes to the creation of a Derivative Work.
|
||||
- The Licensee or You: any natural or legal person who makes any usage of the Work under the terms of the Licence.
|
||||
- Distribution or Communication: any act of selling, giving, lending, renting, distributing, communicating, transmitting, or otherwise making available, online or offline, copies of the Work or providing access to its essential functionalities at the disposal of any other natural or legal person.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
2. Scope of the rights granted by the Licence
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, sublicensable licence to do the following, for the duration of copyright vested in the Original Work:
|
||||
- use the Work in any circumstance and for all usage,
|
||||
- reproduce the Work,
|
||||
- modify the Work, and make Derivative Works based upon the Work,
|
||||
- communicate to the public, including the right to make available or display the Work or copies thereof to the public and perform publicly, as the case may be, the Work,
|
||||
- distribute the Work or copies thereof,
|
||||
- lend and rent the Work or copies thereof,
|
||||
- sublicense rights in the Work or copies thereof.
|
||||
Those rights can be exercised on any media, supports and formats, whether now known or later invented, as far as the applicable law permits so.
|
||||
In the countries where moral rights apply, the Licensor waives his right to exercise his moral right to the extent allowed by law in order to make effective the licence of the economic rights here above listed.
|
||||
The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to any patents held by the Licensor, to the extent necessary to make use of the rights granted on the Work under this Licence.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
3. Communication of the Source Code
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
The Licensor may provide the Work either in its Source Code form, or as Executable Code. If the Work is provided as Executable Code, the Licensor provides in addition a machine-readable copy of the Source Code of the Work along with each copy of the Work that the Licensor distributes or indicates, in a notice following the copyright notice attached to the Work, a repository where the Source Code is easily and freely accessible for as long as the Licensor continues to distribute or communicate the Work.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
4. Limitations on copyright
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
Nothing in this Licence is intended to deprive the Licensee of the benefits from any exception or limitation to the exclusive rights of the rights owners in the Work, of the exhaustion of those rights or of other applicable limitations thereto.
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
5. Obligations of the Licensee
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
The grant of the rights mentioned above is subject to some restrictions and obligations imposed on the Licensee. Those obligations are the following:
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
Attribution right: The Licensee shall keep intact all copyright, patent or trademarks notices and all notices that refer to the Licence and to the disclaimer of warranties. The Licensee must include a copy of such notices and a copy of the Licence with every copy of the Work he/she distributes or communicates. The Licensee must cause any Derivative Work to carry prominent notices stating that the Work has been modified and the date of modification.
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
Copyleft clause: If the Licensee distributes or communicates copies of the Original Works or Derivative Works, this Distribution or Communication will be done under the terms of this Licence or of a later version of this Licence unless the Original Work is expressly distributed only under this version of the Licence - for example by communicating EUPL v. 1.2 only. The Licensee (becoming Licensor) cannot offer or impose any additional terms or conditions on the Work or Derivative Work that alter or restrict the terms of the Licence.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
Compatibility clause: If the Licensee Distributes or Communicates Derivative Works or copies thereof based upon both the Work and another work licensed under a Compatible Licence, this Distribution or Communication can be done under the terms of this Compatible Licence. For the sake of this clause, Compatible Licence refers to the licences listed in the appendix attached to this Licence. Should the Licensee's obligations under the Compatible Licence conflict with his/her obligations under this Licence, the obligations of the Compatible Licence shall prevail.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
Provision of Source Code: When distributing or communicating copies of the Work, the Licensee will provide a machine-readable copy of the Source Code or indicate a repository where this Source will be easily and freely available for as long as the Licensee continues to distribute or communicate the Work.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
Legal Protection: This Licence does not grant permission to use the trade names, trademarks, service marks, or names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the copyright notice.
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
6. Chain of Authorship
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
The original Licensor warrants that the copyright in the Original Work granted hereunder is owned by him/her or licensed to him/her and that he/she has the power and authority to grant the Licence.
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
Each Contributor warrants that the copyright in the modifications he/she brings to the Work are owned by him/her or licensed to him/her and that he/she has the power and authority to grant the Licence.
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
Each time You accept the Licence, the original Licensor and subsequent Contributors grant You a licence to their contributions to the Work, under the terms of this Licence.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
7. Disclaimer of Warranty
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
The Work is a work in progress, which is continuously improved by numerous Contributors. It is not a finished work and may therefore contain defects or bugs inherent to this type of development.
|
||||
For the above reason, the Work is provided under the Licence on an as is basis and without warranties of any kind concerning the Work, including without limitation merchantability, fitness for a particular purpose, absence of defects or errors, accuracy, non-infringement of intellectual property rights other than copyright as stated in Article 6 of this Licence.
|
||||
This disclaimer of warranty is an essential part of the Licence and a condition for the grant of any rights to the Work.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
8. Disclaimer of Liability
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
Except in the cases of wilful misconduct or damages directly caused to natural persons, the Licensor will in no event be liable for any direct or indirect, material or moral, damages of any kind, arising out of the Licence or of the use of the Work, including without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, loss of data or any commercial damage, even if the Licensor has been advised of the possibility of such damage. However, the Licensor will be liable under statutory product liability laws as far such laws apply to the Work.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
9. Additional agreements
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
While distributing the Work, You may choose to conclude an additional agreement, defining obligations or services consistent with this Licence. However, if accepting obligations, You may act only on your own behalf and on your sole responsibility, not on behalf of the original Licensor or any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against such Contributor by the fact You have accepted any warranty or additional liability.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
10. Acceptance of the Licence
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
The provisions of this Licence can be accepted by clicking on an icon I agree placed under the bottom of a window displaying the text of this Licence or by affirming consent in any other similar way, in accordance with the rules of applicable law. Clicking on that icon indicates your clear and irrevocable acceptance of this Licence and all of its terms and conditions.
|
||||
Similarly, you irrevocably accept this Licence and all of its terms and conditions by exercising any rights granted to You by Article 2 of this Licence, such as the use of the Work, the creation by You of a Derivative Work or the Distribution or Communication by You of the Work or copies thereof.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
11. Information to the public
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
In case of any Distribution or Communication of the Work by means of electronic communication by You (for example, by offering to download the Work from a remote location) the distribution channel or media (for example, a website) must at least provide to the public the information requested by the applicable law regarding the Licensor, the Licence and the way it may be accessible, concluded, stored and reproduced by the Licensee.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
12. Termination of the Licence
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
The Licence and the rights granted hereunder will terminate automatically upon any breach by the Licensee of the terms of the Licence.
|
||||
Such a termination will not terminate the licences of any person who has received the Work from the Licensee under the Licence, provided such persons remain in full compliance with the Licence.
|
||||
|
||||
NO WARRANTY
|
||||
13. Miscellaneous
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
Without prejudice of Article 9 above, the Licence represents the complete agreement between the Parties as to the Work.
|
||||
If any provision of the Licence is invalid or unenforceable under applicable law, this will not affect the validity or enforceability of the Licence as a whole. Such provision will be construed or reformed so as necessary to make it valid and enforceable.
|
||||
The European Commission may publish other linguistic versions or new versions of this Licence or updated versions of the Appendix, so far this is required and reasonable, without reducing the scope of the rights granted by the Licence. New versions of the Licence will be published with a unique version number.
|
||||
All linguistic versions of this Licence, approved by the European Commission, have identical value. Parties can take advantage of the linguistic version of their choice.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
14. Jurisdiction
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
Without prejudice to specific agreement between parties,
|
||||
- any litigation resulting from the interpretation of this License, arising between the European Union institutions, bodies, offices or agencies, as a Licensor, and any Licensee, will be subject to the jurisdiction of the Court of Justice of the European Union, as laid down in article 272 of the Treaty on the Functioning of the European Union,
|
||||
- any litigation arising between other parties and resulting from the interpretation of this License, will be subject to the exclusive jurisdiction of the competent court where the Licensor resides or conducts its primary business.
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
15. Applicable Law
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
Without prejudice to specific agreement between parties,
|
||||
- this Licence shall be governed by the law of the European Union Member State where the Licensor has his seat, resides or has his registered office,
|
||||
- this licence shall be governed by Belgian law if the Licensor has no seat, residence or registered office inside a European Union Member State.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
===
|
||||
|
||||
{description}
|
||||
Copyright (C) {year} {fullname}
|
||||
Appendix
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
{signature of Ty Coon}, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
Compatible Licences according to Article 5 EUPL are:
|
||||
- GNU General Public License (GPL) v. 2, v. 3
|
||||
- GNU Affero General Public License (AGPL) v. 3
|
||||
- Open Software License (OSL) v. 2.1, v. 3.0
|
||||
- Eclipse Public License (EPL) v. 1.0
|
||||
- CeCILL v. 2.0, v. 2.1
|
||||
- Mozilla Public Licence (MPL) v. 2
|
||||
- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
|
||||
- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for works other than software
|
||||
- European Union Public Licence (EUPL) v. 1.1, v. 1.2
|
||||
- Québec Free and Open-Source Licence - Reciprocity (LiLiQ-R) or Strong Reciprocity (LiLiQ-R+)
|
||||
- The European Commission may update this Appendix to later versions of the above licences without producing a new version of the EUPL, as long as they provide the rights granted in Article 2 of this Licence and protect the covered Source Code from exclusive appropriation.
|
||||
- All other changes or additions to this Appendix require the production of a new EUPL version.
|
||||
|
188
README.md
188
README.md
@@ -1,68 +1,176 @@
|
||||
# Automated Install
|
||||
<p align="center">
|
||||
<a href=https://www.bountysource.com/trackers/3011939-pi-hole-pi-hole?utm_source=3011939&utm_medium=shield&utm_campaign=TRACKER_BADGE><img src="https://www.bountysource.com/badge/tracker?tracker_id=3011939"></a>
|
||||
<a href="https://www.codacy.com/app/Pi-hole/pi-hole?utm_source=github.com&utm_medium=referral&utm_content=pi-hole/pi-hole&utm_campaign=Badge_Grade"><img src="https://api.codacy.com/project/badge/Grade/c558a0f8d7124c99b02b84f0f5564238"/></a>
|
||||
<a href=https://travis-ci.org/pi-hole/pi-hole><img src="https://travis-ci.org/pi-hole/pi-hole.svg?branch=development"></a>
|
||||
</p>
|
||||
|
||||
1. Install Raspbian
|
||||
2. Run the command below
|
||||
<p align="center">
|
||||
<a href=https://discourse.pi-hole.net><img src="https://assets.pi-hole.net/static/Vortex_with_text_and_TM.png" width=210></a>
|
||||
</p>
|
||||
|
||||
### ```curl -L install.pi-hole.net | bash```
|
||||
## The multi-platform, network-wide ad blocker
|
||||
|
||||

|
||||
Block ads for **all** your devices _without_ the need to install client-side software. The Pi-hole™ blocks ads at the DNS-level, so all your devices are protected.
|
||||
|
||||
Once installed, **configure any device to use the Raspberry Pi as its DNS server and the ads will be blocked**. You can also configure your router's DHCP options to assign the Pi as clients DNS server so they do not need to do it manually.
|
||||
- Web Browsers
|
||||
- Cell Phones
|
||||
- Smart TV's
|
||||
- Internet-connected home automation
|
||||
- Anything that communicates with the Internet
|
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3J2L3Z4DHW9UY "Donate")
|
||||
<p align="center">
|
||||
<a href=http://www.digitalocean.com/?refcode=344d234950e1><img src="https://assets.pi-hole.net/static/DOHostingSlug.png"></a>
|
||||
</p>
|
||||
|
||||
# Raspberry Pi Ad Blocker
|
||||
**A black hole for ads, hence Pi-hole**
|
||||
## Your Support Still Matters
|
||||
|
||||

|
||||
Digital Ocean helps with our infrastructure, but our developers are all volunteers so *your donations help keep us innovating*. Sending a donation using our links below helps us offset a portion of our monthly costs.
|
||||
|
||||
The Pi-hole is a DNS/Web server that will **block ads for any device on your network**.
|
||||
-  [Donate via PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3J2L3Z4DHW9UY)
|
||||
-  Bitcoin Address: 1GKnevUnVaQM2pQieMyeHkpr8DXfkpfAtL
|
||||
|
||||
## Coverage
|
||||
### One-Step Automated Install
|
||||
1. Install a [supported operating system](https://discourse.pi-hole.net/t/hardware-software-requirements/273/1)
|
||||
2. Run the command below (it downloads [this script](https://github.com/pi-hole/pi-hole/blob/master/automated%20install/basic-install.sh) in case you want to read over it first!)
|
||||
|
||||
### Security Now! Podcast
|
||||
Pi-hole is mentioned at 100 minutes and 26 seconds (the link brings you right there)
|
||||
[](http://www.youtube.com/watch?v=p7-osq_y8i8&t=100m26s)
|
||||
### `curl -sSL https://install.pi-hole.net | bash`
|
||||
|
||||
### Tech Blogs
|
||||
#### Alternative Semi-Automated Install Methods
|
||||
_If you wish to read over the script before running it, run `nano basic-install.sh` to open the file in a text viewer._
|
||||
|
||||
Featured on [MakeUseOf](http://www.makeuseof.com/tag/adblock-everywhere-raspberry-pi-hole-way/) and [Lifehacker](http://lifehacker.com/turn-a-raspberry-pi-into-an-ad-blocker-with-a-single-co-1686093533)!
|
||||
##### Clone our repository and run the automated installer from your device.
|
||||
|
||||
```
|
||||
git clone --depth 1 https://github.com/pi-hole/pi-hole.git Pi-hole
|
||||
cd Pi-hole/automated\ install/
|
||||
bash basic-install.sh
|
||||
```
|
||||
|
||||
##### Or
|
||||
|
||||
```bash
|
||||
wget -O basic-install.sh https://install.pi-hole.net
|
||||
bash basic-install.sh
|
||||
```
|
||||
|
||||
Once installed, [configure your router to have **DHCP clients use the Pi 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) and then any device that connects to your network will have ads blocked without any further configuration. Alternatively, you can manually set each device to use Pi-hole™ as their DNS server.
|
||||
|
||||
## What is Pi-hole™ and how do I install it?
|
||||
<p align="center">
|
||||
<a href=https://www.youtube.com/watch?v=vKWjx1AQYgs><img src="https://assets.pi-hole.net/static/video-explainer.png"></a>
|
||||
</p>
|
||||
|
||||
|
||||
## Get Help Or Connect With Us On The Web
|
||||
|
||||
- [Users Forum](https://discourse.pi-hole.net/)
|
||||
- [FAQs](https://discourse.pi-hole.net/c/faqs)
|
||||
- [Wiki](https://github.com/pi-hole/pi-hole/wiki)
|
||||
-  [Tweet @The_Pi_Hole](https://twitter.com/The_Pi_Hole)
|
||||
-  [Reddit /r/pihole](https://www.reddit.com/r/pihole/)
|
||||
-  [Pi-hole channel](https://www.youtube.com/channel/UCT5kq9w0wSjogzJb81C9U0w)
|
||||
- [](https://gitter.im/pi-hole/pi-hole?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
## Technical Details
|
||||
|
||||
A more detailed explanation of the installation can be found [here](http://jacobsalmela.com/block-millions-ads-network-wide-with-a-raspberry-pi-hole-2-0).
|
||||
The Pi-hole™ is an **advertising-aware DNS/Web server**. If an ad domain is queried, a small Web page or GIF is delivered in place of the advertisement.
|
||||
|
||||
## Gravity
|
||||
The [gravity.sh](https://github.com/jacobsalmela/pi-hole/blob/master/gravity.sh) does most of the magic. The script pulls in ad domains from many sources and compiles them into a single list of [over 1.6 million entries](http://jacobsalmela.com/block-millions-ads-network-wide-with-a-raspberry-pi-hole-2-0).
|
||||
### Gravity
|
||||
|
||||
## Whitelist and blacklist
|
||||
You can add a `whitelist.txt` or `blacklist.txt` in `/etc/pihole/` and the script will apply those files automatically.
|
||||
The [gravity.sh](https://github.com/pi-hole/pi-hole/blob/master/gravity.sh) does most of the magic. The script pulls in ad domains from many sources and compiles them into a single list of [over 1.6 million entries](http://jacobsalmela.com/block-millions-ads-network-wide-with-a-raspberry-pi-hole-2-0) (if you decide to use the [mahakala list](https://github.com/pi-hole/pi-hole/commit/963eacfe0537a7abddf30441c754c67ca1e40965)). This script is controlled by the `pihole` command. Please run `pihole -h` to see what commands can be run via `pihole`.
|
||||
|
||||
## Web Interface
|
||||
The [Web interface](https://github.com/jacobsalmela/AdminLTE#pi-hole-admin-dashboard) will be installed automatically so you can view stats and change settings. You can find it at:
|
||||
|
||||
`http://192.168.1.x/admin/index.php`
|
||||
|
||||

|
||||
#### Other Operating Systems
|
||||
|
||||
## Custom Config File
|
||||
If you want to use your own variables for the gravity script (i.e. storing the files in a different location) and don't want to have to change them every time there is an update to the script, create a file called `/etc/pihole/pihole.conf`. In it, you should add your own variables in a similar fashion as shown below:
|
||||
The automated install is only for a clean install of a Debian family or Fedora based system, such as the Raspberry Pi. However, this script will work for most UNIX-like systems, some with some slight **modifications** that we can help you work through. If you can install `dnsmasq` and a web server, it should work OK. If there are other platforms you'd like supported, let us know.
|
||||
|
||||
```
|
||||
origin=/var/run/pihole
|
||||
adList=/etc/dnsmasq.d/adList
|
||||
### Web Interface
|
||||
|
||||
The [Web interface](https://github.com/pi-hole/AdminLTE#pi-hole-admin-dashboard) will be installed automatically so you can view stats and change settings. You can find it at:
|
||||
|
||||
`http://192.168.1.x/admin/index.php` or `http://pi.hole/admin`
|
||||
|
||||

|
||||
|
||||
### Whitelist and blacklist
|
||||
|
||||
Domains can be whitelisted and blacklisted using either the web interface or the command line. See [the wiki page](https://github.com/pi-hole/pi-hole/wiki/Whitelisting-and-Blacklisting) for more details
|
||||
<p align="center">
|
||||
<a href=https://github.com/pi-hole/pi-hole/wiki/Whitelisting-and-Blacklisting><img src="https://assets.pi-hole.net/static/whitelist212.png"></a>
|
||||
</p>
|
||||
|
||||
### Settings
|
||||
|
||||
The settings page lets you control and configure your Pi-hole™. You can do things like:
|
||||
|
||||
- enable Pi-hole's built-in DHCP server
|
||||
- exclude domains from the graphs
|
||||
- configure upstream DNS servers
|
||||
- and more!
|
||||
|
||||

|
||||
|
||||
#### Built-in DHCP Server
|
||||
|
||||
Pi-hole™ ships with a built-in DHCP server. This allows you to let your network devices use Pi-hole™ as their DNS server if your router does not let you adjust the DHCP options.
|
||||
<p align="center">
|
||||
<a href=hhttps://discourse.pi-hole.net/t/how-do-i-configure-my-devices-to-use-pi-hole-as-their-dns-server/245><img src="https://assets.pi-hole.net/static/piholedhcpserver.png"></a>
|
||||
</p>
|
||||
|
||||
## API
|
||||
|
||||
A basic read-only API can be accessed at `/admin/api.php`. It returns the following JSON:
|
||||
|
||||
``` json
|
||||
{
|
||||
"domains_being_blocked": "136708",
|
||||
"dns_queries_today": "18108",
|
||||
"ads_blocked_today": "14648",
|
||||
"ads_percentage_today": "80.89"
|
||||
}
|
||||
```
|
||||
|
||||
See [this PR](https://github.com/jacobsalmela/pi-hole/pull/20) for more details.
|
||||
The same output can be achieved on the CLI by running `chronometer.sh -j`
|
||||
|
||||
### How It Works
|
||||
A technical and detailed description can be found [here](http://jacobsalmela.com/block-millions-ads-network-wide-with-a-raspberry-pi-hole-2-0)!
|
||||
## Real-time Statistics
|
||||
|
||||
## Other Operating Systems
|
||||
This script will work for other UNIX-like systems with some slight **modifications**. As long as you can install `dnsmasq` and a Webserver, it should work OK. The automated install only works for a clean install of Raspiban right now since that is how the project originated.
|
||||
You can view [real-time stats](https://discourse.pi-hole.net/t/how-do-i-view-my-pi-holes-stats-over-ssh-or-on-an-lcd-using-chronometer/240) via `ssh` or on an [2.8" LCD screen](http://amzn.to/1P0q1Fj). This is accomplished via [`chronometer.sh`](https://github.com/pi-hole/pi-hole/blob/master/advanced/Scripts/chronometer.sh). 
|
||||
|
||||
### Examples Of The Pi-hole On Other Operating Systems
|
||||
- [Sky-Hole](http://dlaa.me/blog/post/skyhole)
|
||||
- [Pi-hole in the Cloud!](http://blog.codybunch.com/2015/07/28/Pi-Hole-in-the-cloud/)
|
||||
## Pi-hole™ Projects
|
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3J2L3Z4DHW9UY "Donate")
|
||||
- [An ad blocking Magic Mirror](https://zonksec.com/blog/magic-mirror-dns-filtering/#dnssoftware)
|
||||
- [Pi-hole stats in your Mac's menu bar](https://getbitbar.com/plugins/Network/pi-hole.1m.py)
|
||||
- [Get LED alerts for each blocked ad](http://thetimmy.silvernight.org/pages/endisbutton/)
|
||||
- [Pi-hole on Ubuntu 14.04 on VirtualBox](http://hbalagtas.blogspot.com/2016/02/adblocking-with-pi-hole-and-ubuntu-1404.html)
|
||||
- [Docker Pi-hole container (x86 and ARM)](https://hub.docker.com/r/diginc/pi-hole/)
|
||||
- [Splunk: Pi-hole Visualiser](https://splunkbase.splunk.com/app/3023/)
|
||||
- [Pi-hole Chrome extension](https://chrome.google.com/webstore/detail/pi-hole-list-editor/hlnoeoejkllgkjbnnnhfolapllcnaglh) ([open source](https://github.com/packtloss/pihole-extension))
|
||||
- [Go Bananas for CHiP-hole ad blocking](https://www.hackster.io/jacobsalmela/chip-hole-network-wide-ad-blocker-98e037)
|
||||
- [Sky-Hole](http://dlaa.me/blog/post/skyhole)
|
||||
- [Pi-hole in the Cloud!](http://blog.codybunch.com/2015/07/28/Pi-Hole-in-the-cloud/)
|
||||
- [unRaid-hole](https://github.com/spants/unraidtemplates/blob/master/Spants/unRaid-hole.xml#L13)--[Repo and more info](http://lime-technology.com/forum/index.php?PHPSESSID=c0eae3e5ef7e521f7866034a3336489d&topic=38486.0)
|
||||
- [Pi-hole on/off button](http://thetimmy.silvernight.org/pages/endisbutton/)
|
||||
- [Minibian Pi-hole](http://munkjensen.net/wiki/index.php/See_my_Pi-Hole#Minibian_Pi-hole)
|
||||
- [Windows Tray Stat Application](https://github.com/goldbattle/copernicus)
|
||||
- [Let your blink1 device blink when Pi-hole filters ads](https://gist.github.com/elpatron68/ec0b4c582e5abf604885ac1e068d233f)
|
||||
- [Pi-hole Prometheus exporter](https://github.com/nlamirault/pihole_exporter): a [Prometheus](https://prometheus.io/) exporter for Pi-hole
|
||||
- [Pi-hole Droid - open source Android client](https://github.com/friimaind/pi-hole-droid)
|
||||
- [Windows DNS Swapper](https://github.com/roots84/DNS-Swapper), see [#1400](https://github.com/pi-hole/pi-hole/issues/1400)
|
||||
|
||||
## Coverage
|
||||
|
||||
- [Adafruit livestream install](https://www.youtube.com/watch?v=eg4u2j1HYlI)
|
||||
- [TekThing: 5 fun, easy projects for a Raspberry Pi](https://youtu.be/QwrKlyC2kdM?t=1m42s)
|
||||
- [Pi-hole on Adafruit's blog](https://blog.adafruit.com/2016/03/04/pi-hole-is-a-black-hole-for-internet-ads-piday-raspberrypi-raspberry_pi/)
|
||||
- [The Defrag Show - MSDN/Channel 9](https://channel9.msdn.com/Shows/The-Defrag-Show/Defrag-Endoscope-USB-Camera-The-Final-HoloLens-Vote-Adblock-Pi-and-more?WT.mc_id=dlvr_twitter_ch9#time=20m39s)
|
||||
- [MacObserver Podcast 585](http://www.macobserver.com/tmo/podcast/macgeekgab-585)
|
||||
- [Medium: Block All Ads For $53](https://medium.com/@robleathern/block-ads-on-all-home-devices-for-53-18-a5f1ec139693#.gj1xpgr5d)
|
||||
- [MakeUseOf: Adblock Everywhere, The Pi-hole Way](http://www.makeuseof.com/tag/adblock-everywhere-raspberry-pi-hole-way/)
|
||||
- [Lifehacker: Turn Your Pi Into An Ad Blocker With A Single Command](http://lifehacker.com/turn-a-raspberry-pi-into-an-ad-blocker-with-a-single-co-1686093533)!
|
||||
- [Pi-hole on TekThing](https://youtu.be/8Co59HU2gY0?t=2m)
|
||||
- [Pi-hole on Security Now! Podcast](http://www.youtube.com/watch?v=p7-osq_y8i8&t=100m26s)
|
||||
- [Foolish Tech Show](https://youtu.be/bYyena0I9yc?t=2m4s)
|
||||
- [Pi-hole on Ubuntu](http://www.boyter.org/2015/12/pi-hole-ubuntu-14-04/)
|
||||
- [Catchpoint: iOS 9 Ad Blocking](http://blog.catchpoint.com/2015/09/14/ad-blocking-apple/)
|
||||
- [Build an Ad-Blocker for less than 10$ with Orange-Pi](http://www.devacron.com/orangepi-zero-as-an-ad-block-server-with-pi-hole/)
|
||||
|
23
adlists.default
Normal file
23
adlists.default
Normal file
@@ -0,0 +1,23 @@
|
||||
# The below list amalgamates several lists we used previously.
|
||||
# See `https://github.com/StevenBlack/hosts` for details
|
||||
##StevenBlack's list
|
||||
https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
|
||||
|
||||
##MalwareDomains
|
||||
https://mirror1.malwaredomains.com/files/justdomains
|
||||
|
||||
##Cameleon
|
||||
http://sysctl.org/cameleon/hosts
|
||||
|
||||
##Zeustracker
|
||||
https://zeustracker.abuse.ch/blocklist.php?download=domainblocklist
|
||||
|
||||
##Disconnect.me Tracking
|
||||
https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt
|
||||
|
||||
##Disconnect.me Ads
|
||||
https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt
|
||||
|
||||
##Hosts-file.net
|
||||
https://hosts-file.net/ad_servers.txt
|
||||
|
47
advanced/01-pihole.conf
Normal file
47
advanced/01-pihole.conf
Normal file
@@ -0,0 +1,47 @@
|
||||
# Pi-hole: A black hole for Internet advertisements
|
||||
# (c) 2015, 2016 by Jacob Salmela
|
||||
# Network-wide ad blocking via your Raspberry Pi
|
||||
# http://pi-hole.net
|
||||
# dnsmasq config for Pi-hole
|
||||
#
|
||||
# Pi-hole is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
###############################################################################
|
||||
# FILE AUTOMATICALLY POPULATED BY PI-HOLE INSTALL/UPDATE PROCEDURE. #
|
||||
# ANY CHANGES MADE TO THIS FILE AFTER INSTALL WILL BE LOST ON THE NEXT UPDATE #
|
||||
# #
|
||||
# IF YOU WISH TO CHANGE THE UPSTREAM SERVERS, CHANGE THEM IN: #
|
||||
# /etc/pihole/setupVars.conf #
|
||||
# #
|
||||
# ANY OTHER CHANGES SHOULD BE MADE IN A SEPERATE CONFIG FILE #
|
||||
# OR IN /etc/dnsmasq.conf #
|
||||
###############################################################################
|
||||
|
||||
addn-hosts=/etc/pihole/gravity.list
|
||||
addn-hosts=/etc/pihole/local.list
|
||||
addn-hosts=/etc/pihole/black.list
|
||||
|
||||
domain-needed
|
||||
|
||||
localise-queries
|
||||
|
||||
bogus-priv
|
||||
|
||||
no-resolv
|
||||
|
||||
server=@DNS1@
|
||||
server=@DNS2@
|
||||
|
||||
interface=@INT@
|
||||
|
||||
cache-size=10000
|
||||
|
||||
log-queries
|
||||
log-facility=/var/log/pihole.log
|
||||
|
||||
local-ttl=300
|
||||
|
||||
log-async
|
@@ -1,28 +1,435 @@
|
||||
#!/bin/bash
|
||||
# Displays Pi-hole stats on the Adafruit PiTFT 2.8" touch screen
|
||||
# Set the pi user to log in automatically and run this script from /etc/profile
|
||||
for (( ; ; ))
|
||||
do
|
||||
clear
|
||||
# Displays a colorful Pi-hole logo
|
||||
toilet -f small -F gay Pi-hole
|
||||
echo " $(ifconfig eth0 | awk '/inet addr/ {print $2}' | cut -d':' -f2)"
|
||||
echo ""
|
||||
uptime | cut -d' ' -f11-
|
||||
echo "-------------------------------"
|
||||
# Uncomment to continually read the log file and display the current domain being blocked
|
||||
#tail -f /var/log/pihole.log | awk '/\/etc\/pihole\/gravity.list/ {if ($7 != "address" && $7 != "name" && $7 != "/etc/pihole/gravity.list") print $7; else;}'
|
||||
|
||||
today=$(date "+%b %e")
|
||||
todaysQueryCount=$(cat /var/log/pihole.log | grep "$today" | awk '/query/ {print $7}' | wc -l)
|
||||
todaysQueryCountV4=$(cat /var/log/pihole.log | grep "$today" | awk '/query/ && /\[A\]/ {print $7}' | wc -l)
|
||||
todaysQueryCountV6=$(cat /var/log/pihole.log | grep "$today" | awk '/query/ && /\[AAAA\]/ {print $7}' | wc -l)
|
||||
todaysAdsEliminated=$(cat /var/log/pihole.log | grep "$today" | awk '/\/etc\/pihole\/gravity.list/ {print $7}' | wc -l)
|
||||
dividend=$(echo "$todaysAdsEliminated/$todaysQueryCount" | bc -l)
|
||||
fp=$(echo "$dividend*100" | bc -l)
|
||||
percentAds=$(echo ${fp:0:4})
|
||||
|
||||
echo "Queries: $todaysQueryCountV4 / $todaysQueryCountV6"
|
||||
echo "Pi-holed: $todaysAdsEliminated ($percentAds%)"
|
||||
sleep 5
|
||||
#!/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.
|
||||
#
|
||||
# Calculates stats and displays to an LCD
|
||||
#
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
# Retrieve stats from FTL engine
|
||||
pihole-FTL() {
|
||||
ftl_port=$(cat /var/run/pihole-FTL.port 2> /dev/null)
|
||||
if [[ -n "$ftl_port" ]]; then
|
||||
# Open connection to FTL
|
||||
exec 3<>"/dev/tcp/localhost/$ftl_port"
|
||||
|
||||
# Test if connection is open
|
||||
if { "true" >&3; } 2> /dev/null; then
|
||||
# Send command to FTL
|
||||
echo -e ">$1" >&3
|
||||
|
||||
# Read input
|
||||
read -r -t 1 LINE <&3
|
||||
until [[ ! $? ]] || [[ "$LINE" == *"EOM"* ]]; do
|
||||
echo "$LINE" >&1
|
||||
read -r -t 1 LINE <&3
|
||||
done
|
||||
|
||||
# Close connection
|
||||
exec 3>&-
|
||||
exec 3<&-
|
||||
fi
|
||||
else
|
||||
echo -e "${COL_LIGHT_RED}FTL offline${COL_NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Print spaces to align right-side content
|
||||
printFunc() {
|
||||
txt_len="${#2}"
|
||||
|
||||
# Reduce string length when using colour code
|
||||
[ "${2:0:1}" == "" ] && txt_len=$((txt_len-7))
|
||||
|
||||
if [[ "$3" == "last" ]]; then
|
||||
# Prevent final line from printing trailing newline
|
||||
scr_size=( $(stty size 2>/dev/null || echo 24 80) )
|
||||
scr_width="${scr_size[1]}"
|
||||
|
||||
title_len="${#1}"
|
||||
spc_num=$(( (scr_width - title_len) - txt_len ))
|
||||
[[ "$spc_num" -lt 0 ]] && spc_num="0"
|
||||
spc=$(printf "%${spc_num}s")
|
||||
|
||||
printf "%s%s$spc" "$1" "$2"
|
||||
else
|
||||
# Determine number of spaces for padding
|
||||
spc_num=$(( 20 - txt_len ))
|
||||
[[ "$spc_num" -lt 0 ]] && spc_num="0"
|
||||
spc=$(printf "%${spc_num}s")
|
||||
|
||||
# Print string (Max 20 characters, prevents overflow)
|
||||
printf "%s%s$spc" "$1" "${2:0:20}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Perform on first Chrono run (not for JSON formatted string)
|
||||
get_init_stats() {
|
||||
LC_NUMERIC=C
|
||||
calcFunc(){ awk "BEGIN {print $*}"; }
|
||||
|
||||
# Convert bytes to human-readable format
|
||||
hrBytes() {
|
||||
awk '{
|
||||
num=$1;
|
||||
if(num==0) {
|
||||
print "0 B"
|
||||
} else {
|
||||
xxx=(num<0?-num:num)
|
||||
sss=(num<0?-1:1)
|
||||
split("B KB MB GB TB PB",type)
|
||||
for(i=5;yyy < 1;i--) {
|
||||
yyy=xxx / (2^(10*i))
|
||||
}
|
||||
printf "%.0f " type[i+2], yyy*sss
|
||||
}
|
||||
}' <<< "$1";
|
||||
}
|
||||
|
||||
# Convert seconds to human-readable format
|
||||
hrSecs() {
|
||||
day=$(( $1/60/60/24 )); hrs=$(( $1/3600%24 )); mins=$(( ($1%3600)/60 )); secs=$(( $1%60 ))
|
||||
[[ "$day" -ge "2" ]] && plu="s"
|
||||
[[ "$day" -ge "1" ]] && days="$day day${plu}, " || days=""
|
||||
printf "%s%02d:%02d:%02d\n" "$days" "$hrs" "$mins" "$secs"
|
||||
}
|
||||
|
||||
# Set Colour Codes
|
||||
coltable="/opt/pihole/COL_TABLE"
|
||||
if [[ -f "${coltable}" ]]; then
|
||||
source ${coltable}
|
||||
else
|
||||
COL_NC='[0m'
|
||||
COL_DARK_GRAY='[1;30m'
|
||||
COL_LIGHT_GREEN='[1;32m'
|
||||
COL_LIGHT_BLUE='[1;34m'
|
||||
COL_LIGHT_RED='[1;31m'
|
||||
COL_YELLOW='[1;33m'
|
||||
COL_LIGHT_RED='[1;31m'
|
||||
COL_URG_RED='[39;41m'
|
||||
fi
|
||||
|
||||
# Get RPi model number, or OS distro info
|
||||
if command -v vcgencmd &> /dev/null; then
|
||||
sys_rev=$(awk '/Revision/ {print $3}' < /proc/cpuinfo)
|
||||
case "$sys_rev" in
|
||||
000[2-6]) sys_model=" 1, Model B";; # 256MB
|
||||
000[7-9]) sys_model=" 1, Model A" ;; # 256MB
|
||||
000d|000e|000f) sys_model=" 1, Model B";; # 512MB
|
||||
0010|0013) sys_model=" 1, Model B+";; # 512MB
|
||||
0012|0015) sys_model=" 1, Model A+";; # 256MB
|
||||
a0104[0-1]|a21041|a22042) sys_model=" 2, Model B";; # 1GB
|
||||
900021) sys_model=" 1, Model A+";; # 512MB
|
||||
900032) sys_model=" 1, Model B+";; # 512MB
|
||||
90009[2-3]|920093) sys_model=" Zero";; # 512MB
|
||||
9000c1) sys_model=" Zero W";; # 512MB
|
||||
a02082|a[2-3]2082) sys_model=" 3, Model B";; # 1GB
|
||||
*) sys_model="" ;;
|
||||
esac
|
||||
sys_type="Raspberry Pi$sys_model"
|
||||
else
|
||||
source "/etc/os-release"
|
||||
CODENAME=$(sed 's/[()]//g' <<< "${VERSION/* /}")
|
||||
sys_type="${NAME/ */} ${CODENAME^} $VERSION_ID"
|
||||
fi
|
||||
|
||||
# Get core count
|
||||
sys_cores=$(grep -c "^processor" /proc/cpuinfo)
|
||||
[[ "$sys_cores" -ne 1 ]] && sys_cores_plu="cores" || sys_cores_plu="core"
|
||||
|
||||
# Test existence of clock speed file for ARM CPU
|
||||
if [[ -f "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" ]]; then
|
||||
scaling_freq_file="/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"
|
||||
fi
|
||||
|
||||
# Test existence of temperature file
|
||||
if [[ -f "/sys/class/thermal/thermal_zone0/temp" ]]; then
|
||||
temp_file="/sys/class/thermal/thermal_zone0/temp"
|
||||
elif [[ -f "/sys/class/hwmon/hwmon0/temp1_input" ]]; then
|
||||
temp_file="/sys/class/hwmon/hwmon0/temp1_input"
|
||||
else
|
||||
temp_file=""
|
||||
fi
|
||||
|
||||
# Test existence of setupVars config
|
||||
if [[ -f "/etc/pihole/setupVars.conf" ]]; then
|
||||
setupVars="/etc/pihole/setupVars.conf"
|
||||
fi
|
||||
}
|
||||
|
||||
get_sys_stats() {
|
||||
local ph_ver_raw
|
||||
local cpu_raw
|
||||
local ram_raw
|
||||
local disk_raw
|
||||
|
||||
# Update every 12 refreshes (Def: every 60s)
|
||||
count=$((count+1))
|
||||
if [[ "$count" == "1" ]] || (( "$count" % 12 == 0 )); then
|
||||
[[ -n "$setupVars" ]] && source "$setupVars"
|
||||
|
||||
|
||||
ph_ver_raw=($(pihole -v -c 2> /dev/null | sed -n 's/^.* v/v/p'))
|
||||
if [[ -n "${ph_ver_raw[0]}" ]]; then
|
||||
ph_core_ver="${ph_ver_raw[0]}"
|
||||
ph_lte_ver="${ph_ver_raw[1]}"
|
||||
ph_ftl_ver="${ph_ver_raw[2]}"
|
||||
else
|
||||
ph_core_ver="${COL_LIGHT_RED}API unavailable${COL_NC}"
|
||||
fi
|
||||
|
||||
sys_name=$(hostname)
|
||||
|
||||
[[ -n "$TEMPERATUREUNIT" ]] && temp_unit="$TEMPERATUREUNIT" || temp_unit="c"
|
||||
|
||||
# Get storage stats for partition mounted on /
|
||||
disk_raw=($(df -B1 / 2> /dev/null | awk 'END{ print $3,$2,$5 }'))
|
||||
disk_used="${disk_raw[0]}"
|
||||
disk_total="${disk_raw[1]}"
|
||||
disk_perc="${disk_raw[2]}"
|
||||
|
||||
net_gateway=$(route -n | awk '$4 == "UG" {print $2;exit}')
|
||||
|
||||
# Get DHCP stats, if feature is enabled
|
||||
if [[ "$DHCP_ACTIVE" == "true" ]]; then
|
||||
ph_dhcp_eip="${DHCP_END##*.}"
|
||||
ph_dhcp_max=$(( ${DHCP_END##*.} - ${DHCP_START##*.} + 1 ))
|
||||
fi
|
||||
|
||||
# Get alt DNS server, or print total count of alt DNS servers
|
||||
if [[ -z "${PIHOLE_DNS_3}" ]]; then
|
||||
ph_alts="${PIHOLE_DNS_2}"
|
||||
else
|
||||
dns_count="0"
|
||||
[[ -n "${PIHOLE_DNS_2}" ]] && dns_count=$((dns_count+1))
|
||||
[[ -n "${PIHOLE_DNS_3}" ]] && dns_count=$((dns_count+1))
|
||||
[[ -n "${PIHOLE_DNS_4}" ]] && dns_count=$((dns_count+1))
|
||||
[[ -n "${PIHOLE_DNS_5}" ]] && dns_count=$((dns_count+1))
|
||||
[[ -n "${PIHOLE_DNS_6}" ]] && dns_count=$((dns_count+1))
|
||||
[[ -n "${PIHOLE_DNS_7}" ]] && dns_count=$((dns_count+1))
|
||||
[[ -n "${PIHOLE_DNS_8}" ]] && dns_count=$((dns_count+1))
|
||||
[[ -n "${PIHOLE_DNS_9}" ]] && dns_count="$dns_count+"
|
||||
ph_alts="${dns_count} others"
|
||||
fi
|
||||
fi
|
||||
|
||||
sys_uptime=$(hrSecs "$(cut -d. -f1 /proc/uptime)")
|
||||
sys_loadavg=$(cut -d " " -f1,2,3 /proc/loadavg)
|
||||
|
||||
# Get CPU usage, only counting processes over 1% CPU as active
|
||||
cpu_raw=$(ps -eo pcpu,rss --no-headers | grep -E -v " 0")
|
||||
cpu_tasks=$(wc -l <<< "$cpu_raw")
|
||||
cpu_taskact=$(sed -r "/(^ 0.)/d" <<< "$cpu_raw" | wc -l)
|
||||
cpu_perc=$(awk '{sum+=$1} END {printf "%.0f\n", sum/'"$sys_cores"'}' <<< "$cpu_raw")
|
||||
|
||||
# Get CPU clock speed
|
||||
if [[ -n "$scaling_freq_file" ]]; then
|
||||
cpu_mhz=$(( $(< /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq) / 1000 ))
|
||||
else
|
||||
cpu_mhz=$(lscpu | awk -F "[ .]+" '/MHz/ {print $4;exit}')
|
||||
fi
|
||||
|
||||
# Determine correct string format for CPU clock speed
|
||||
if [[ -n "$cpu_mhz" ]]; then
|
||||
[[ "$cpu_mhz" -le "999" ]] && cpu_freq="$cpu_mhz MHz" || cpu_freq="$(calcFunc "$cpu_mhz"/1000) Ghz"
|
||||
[[ -n "$cpu_freq" ]] && cpu_freq_str=" @ $cpu_freq" || cpu_freq_str=""
|
||||
fi
|
||||
|
||||
# Determine colour for temperature
|
||||
if [[ -n "$temp_file" ]]; then
|
||||
if [[ "$temp_unit" == "C" ]]; then
|
||||
cpu_temp=$(printf "%'.0fc\n" "$(calcFunc "$(< $temp_file) / 1000")")
|
||||
|
||||
case "${cpu_temp::-1}" in
|
||||
-*|[0-9]|[1-3][0-9]) cpu_col="$COL_LIGHT_BLUE";;
|
||||
4[0-9]) cpu_col="";;
|
||||
5[0-9]) cpu_col="$COL_YELLOW";;
|
||||
6[0-9]) cpu_col="$COL_LIGHT_RED";;
|
||||
*) cpu_col="$COL_URG_RED";;
|
||||
esac
|
||||
|
||||
# $COL_NC$COL_DARK_GRAY is needed for $COL_URG_RED
|
||||
cpu_temp_str=", $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY"
|
||||
|
||||
elif [[ "$temp_unit" == "F" ]]; then
|
||||
cpu_temp=$(printf "%'.0ff\n" "$(calcFunc "($(< $temp_file) / 1000) * 9 / 5 + 32")")
|
||||
|
||||
case "${cpu_temp::-1}" in
|
||||
-*|[0-9]|[0-9][0-9]) cpu_col="$COL_LIGHT_BLUE";;
|
||||
1[0-1][0-9]) cpu_col="";;
|
||||
1[2-3][0-9]) cpu_col="$COL_YELLOW";;
|
||||
1[4-5][0-9]) cpu_col="$COL_LIGHT_RED";;
|
||||
*) cpu_col="$COL_URG_RED";;
|
||||
esac
|
||||
|
||||
cpu_temp_str=", $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY"
|
||||
|
||||
else
|
||||
cpu_temp_str=$(printf ", %'.0fk\n" "$(calcFunc "($(< $temp_file) / 1000) + 273.15")")
|
||||
fi
|
||||
else
|
||||
cpu_temp_str=""
|
||||
fi
|
||||
|
||||
ram_raw=($(awk '/MemTotal:/{total=$2} /MemFree:/{free=$2} /Buffers:/{buffers=$2} /^Cached:/{cached=$2} END {printf "%.0f %.0f %.0f", (total-free-buffers-cached)*100/total, (total-free-buffers-cached)*1024, total*1024}' /proc/meminfo))
|
||||
ram_perc="${ram_raw[0]}"
|
||||
ram_used="${ram_raw[1]}"
|
||||
ram_total="${ram_raw[2]}"
|
||||
|
||||
if [[ "$(pihole status web 2> /dev/null)" == "1" ]]; then
|
||||
ph_status="${COL_LIGHT_GREEN}Active"
|
||||
else
|
||||
ph_status="${COL_LIGHT_RED}Inactive"
|
||||
fi
|
||||
|
||||
if [[ "$DHCP_ACTIVE" == "true" ]]; then
|
||||
ph_dhcp_num=$(wc -l 2> /dev/null < "/etc/pihole/dhcp.leases")
|
||||
fi
|
||||
}
|
||||
|
||||
get_ftl_stats() {
|
||||
local stats_raw
|
||||
|
||||
stats_raw=($(pihole-FTL "stats"))
|
||||
domains_being_blocked_raw="${stats_raw[1]}"
|
||||
dns_queries_today_raw="${stats_raw[3]}"
|
||||
ads_blocked_today_raw="${stats_raw[5]}"
|
||||
ads_percentage_today_raw="${stats_raw[7]}"
|
||||
|
||||
# Only retrieve these stats when not called from jsonFunc
|
||||
if [[ -z "$1" ]]; then
|
||||
local recent_blocked_raw
|
||||
local top_ad_raw
|
||||
local top_domain_raw
|
||||
local top_client_raw
|
||||
|
||||
domains_being_blocked=$(printf "%'.0f\n" "${domains_being_blocked_raw}")
|
||||
dns_queries_today=$(printf "%'.0f\n" "${dns_queries_today_raw}")
|
||||
ads_blocked_today=$(printf "%'.0f\n" "${ads_blocked_today_raw}")
|
||||
ads_percentage_today=$(printf "%'.0f\n" "${ads_percentage_today_raw}")
|
||||
|
||||
recent_blocked_raw=$(pihole-FTL recentBlocked)
|
||||
top_ad_raw=($(pihole-FTL "top-ads (1)"))
|
||||
top_domain_raw=($(pihole-FTL "top-domains (1)"))
|
||||
top_client_raw=($(pihole-FTL "top-clients (1)"))
|
||||
|
||||
# Limit strings to 40 characters to prevent overflow
|
||||
recent_blocked="${recent_blocked_raw:0:40}"
|
||||
top_ad="${top_ad_raw[2]:0:40}"
|
||||
top_domain="${top_domain_raw[2]:0:40}"
|
||||
[[ "${top_client_raw[3]}" ]] && top_client="${top_client_raw[3]:0:40}" || top_client="${top_client_raw[2]:0:40}"
|
||||
fi
|
||||
}
|
||||
|
||||
chronoFunc() {
|
||||
get_init_stats
|
||||
|
||||
for (( ; ; )); do
|
||||
get_sys_stats
|
||||
get_ftl_stats
|
||||
|
||||
# Do not print LTE/FTL strings if API is unavailable
|
||||
ph_core_str=" ${COL_DARK_GRAY}Pi-hole: $ph_core_ver${COL_NC}"
|
||||
if [[ -n "$ph_lte_ver" ]]; then
|
||||
ph_lte_str=" ${COL_DARK_GRAY}AdminLTE: $ph_lte_ver${COL_NC}"
|
||||
ph_ftl_str=" ${COL_DARK_GRAY}FTL: $ph_ftl_ver${COL_NC}"
|
||||
fi
|
||||
|
||||
clear
|
||||
|
||||
echo -e "[0;1;31;91m|¯[0;1;33;93m¯[0;1;32;92m¯[0;1;32;92m(¯[0;1;36;96m)_[0;1;34;94m_[0;1;35;95m|[0;1;33;93m¯[0;1;31;91m|_ [0;1;32;92m__[0;1;36;96m_|[0;1;31;91m¯[0;1;34;94m|[0;1;35;95m__[0;1;31;91m_[0m$ph_core_str
|
||||
[0;1;33;93m| ¯[0;1;32;92m_[0;1;36;96m/¯[0;1;34;94m|_[0;1;35;95m_[0;1;31;91m| [0;1;33;93m' [0;1;32;92m\/ [0;1;36;96m_ [0;1;34;94m\ [0;1;35;95m/ [0;1;31;91m-[0;1;33;93m_)[0m$ph_lte_str
|
||||
[0;1;32;92m|_[0;1;36;96m| [0;1;34;94m|_[0;1;35;95m| [0;1;33;93m|_[0;1;32;92m||[0;1;36;96m_\[0;1;34;94m__[0;1;35;95m_/[0;1;31;91m_\[0;1;33;93m__[0;1;32;92m_|[0m$ph_ftl_str
|
||||
${COL_DARK_GRAY}——————————————————————————————————————————————————————————${COL_NC}"
|
||||
|
||||
printFunc " Hostname: " "$sys_name"
|
||||
[ -n "$sys_type" ] && printf "%s(%s)%s\n" "$COL_DARK_GRAY" "$sys_type" "$COL_NC" || printf "\n"
|
||||
|
||||
printf "%s\n" " Uptime: $sys_uptime"
|
||||
|
||||
printFunc " Task Load: " "$sys_loadavg"
|
||||
printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Active: $cpu_taskact of $cpu_tasks tasks" "$COL_NC"
|
||||
|
||||
printFunc " CPU usage: " "$cpu_perc%"
|
||||
printf "%s(%s)%s\n" "$COL_DARK_GRAY" "$sys_cores $sys_cores_plu$cpu_freq_str$cpu_temp_str" "$COL_NC"
|
||||
|
||||
printFunc " RAM usage: " "$ram_perc%"
|
||||
printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Used: $(hrBytes "$ram_used") of $(hrBytes "$ram_total")" "$COL_NC"
|
||||
|
||||
printFunc " HDD usage: " "$disk_perc"
|
||||
printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Used: $(hrBytes "$disk_used") of $(hrBytes "$disk_total")" "$COL_NC"
|
||||
|
||||
printFunc " LAN addr: " "${IPV4_ADDRESS/\/*/}"
|
||||
printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Gateway: $net_gateway" "$COL_NC"
|
||||
|
||||
if [[ "$DHCP_ACTIVE" == "true" ]]; then
|
||||
printFunc " DHCP: " "$DHCP_START to $ph_dhcp_eip"
|
||||
printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Leased: $ph_dhcp_num of $ph_dhcp_max" "$COL_NC"
|
||||
fi
|
||||
|
||||
printFunc " Pi-hole: " "$ph_status"
|
||||
printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Blocking: $domains_being_blocked sites" "$COL_NC"
|
||||
|
||||
printFunc " Ads Today: " "$ads_percentage_today%"
|
||||
printf "%s(%s)%s\n" "$COL_DARK_GRAY" "$ads_blocked_today of $dns_queries_today queries" "$COL_NC"
|
||||
|
||||
printFunc " Fwd DNS: " "$PIHOLE_DNS_1"
|
||||
printf "%s(%s)%s\n" "$COL_DARK_GRAY" "Alt DNS: $ph_alts" "$COL_NC"
|
||||
|
||||
echo -e " ${COL_DARK_GRAY}——————————————————————————————————————————————————————————${COL_NC}"
|
||||
echo " Recently blocked: $recent_blocked"
|
||||
echo " Top Advertiser: $top_ad"
|
||||
echo " Top Domain: $top_domain"
|
||||
printFunc " Top Client: " "$top_client" "last"
|
||||
|
||||
if [[ "$1" == "exit" ]]; then
|
||||
exit 0
|
||||
else
|
||||
if [[ -n "$1" ]]; then
|
||||
sleep "${1}"
|
||||
else
|
||||
sleep 5
|
||||
fi
|
||||
fi
|
||||
|
||||
done
|
||||
}
|
||||
|
||||
jsonFunc() {
|
||||
get_ftl_stats "json"
|
||||
echo "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today_raw}}"
|
||||
}
|
||||
|
||||
helpFunc() {
|
||||
if [[ "$1" == "?" ]]; then
|
||||
echo "Unknown option. Please view 'pihole -c --help' for more information"
|
||||
else
|
||||
echo "Usage: pihole -c [options]
|
||||
Example: 'pihole -c -j'
|
||||
Calculates stats and displays to an LCD
|
||||
|
||||
Options:
|
||||
-j, --json Output stats as JSON formatted string
|
||||
-r, --refresh Set update frequency (in seconds)
|
||||
-e, --exit Output stats and exit witout refreshing
|
||||
-h, --help Display this help text"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
if [[ $# = 0 ]]; then
|
||||
chronoFunc
|
||||
fi
|
||||
|
||||
for var in "$@"; do
|
||||
case "$var" in
|
||||
"-j" | "--json" ) jsonFunc;;
|
||||
"-h" | "--help" ) helpFunc;;
|
||||
"-r" | "--refresh" ) chronoFunc "$2";;
|
||||
"-e" | "--exit" ) chronoFunc "exit";;
|
||||
* ) helpFunc "?";;
|
||||
esac
|
||||
done
|
||||
|
225
advanced/Scripts/list.sh
Executable file
225
advanced/Scripts/list.sh
Executable file
@@ -0,0 +1,225 @@
|
||||
#!/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.
|
||||
#
|
||||
# Whitelist and blacklist domains
|
||||
#
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
# Globals
|
||||
basename=pihole
|
||||
piholeDir=/etc/${basename}
|
||||
whitelist=${piholeDir}/whitelist.txt
|
||||
blacklist=${piholeDir}/blacklist.txt
|
||||
readonly wildcardlist="/etc/dnsmasq.d/03-pihole-wildcard.conf"
|
||||
reload=false
|
||||
addmode=true
|
||||
verbose=true
|
||||
|
||||
domList=()
|
||||
domToRemoveList=()
|
||||
|
||||
listMain=""
|
||||
listAlt=""
|
||||
|
||||
helpFunc() {
|
||||
if [[ "${listMain}" == "${whitelist}" ]]; then
|
||||
param="w"
|
||||
type="white"
|
||||
elif [[ "${listMain}" == "${wildcardlist}" ]]; then
|
||||
param="wild"
|
||||
type="wildcard black"
|
||||
else
|
||||
param="b"
|
||||
type="black"
|
||||
fi
|
||||
|
||||
echo "Usage: pihole -${param} [options] <domain> <domain2 ...>
|
||||
Example: 'pihole -${param} site.com', or 'pihole -${param} site1.com site2.com'
|
||||
${type^}list one or more domains
|
||||
|
||||
Options:
|
||||
-d, --delmode Remove domain(s) from the ${type}list
|
||||
-nr, --noreload Update ${type}list without refreshing dnsmasq
|
||||
-q, --quiet Make output less verbose
|
||||
-h, --help Show this help dialog
|
||||
-l, --list Display all your ${type}listed domains"
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
EscapeRegexp() {
|
||||
# This way we may safely insert an arbitrary
|
||||
# string in our regular expressions
|
||||
# Also remove leading "." if present
|
||||
echo $* | sed 's/^\.*//' | sed "s/[]\.|$(){}?+*^]/\\\\&/g" | sed "s/\\//\\\\\//g"
|
||||
}
|
||||
|
||||
HandleOther() {
|
||||
# First, convert everything to lowercase
|
||||
domain=$(sed -e "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/" <<< "$1")
|
||||
|
||||
# Check validity of domain
|
||||
validDomain=$(echo "${domain}" | perl -lne 'print if /(?!.*[^a-z0-9-\.].*)^((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9-]+\.)*[a-z]{2,63}/')
|
||||
if [[ -z "${validDomain}" ]]; then
|
||||
echo "::: $1 is not a valid argument or domain name"
|
||||
else
|
||||
domList=("${domList[@]}" ${validDomain})
|
||||
fi
|
||||
}
|
||||
|
||||
PoplistFile() {
|
||||
# Check whitelist file exists, and if not, create it
|
||||
if [[ ! -f ${whitelist} ]]; then
|
||||
touch ${whitelist}
|
||||
fi
|
||||
|
||||
for dom in "${domList[@]}"; do
|
||||
# Logic: If addmode then add to desired list and remove from the other; if delmode then remove from desired list but do not add to the other
|
||||
if ${addmode}; then
|
||||
AddDomain "${dom}" "${listMain}"
|
||||
RemoveDomain "${dom}" "${listAlt}"
|
||||
if [[ "${listMain}" == "${whitelist}" || "${listMain}" == "${blacklist}" ]]; then
|
||||
RemoveDomain "${dom}" "${wildcardlist}"
|
||||
fi
|
||||
else
|
||||
RemoveDomain "${dom}" "${listMain}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
AddDomain() {
|
||||
list="$2"
|
||||
domain=$(EscapeRegexp "$1")
|
||||
|
||||
if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then
|
||||
bool=true
|
||||
# Is the domain in the list we want to add it to?
|
||||
grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false
|
||||
|
||||
if [[ "${bool}" == false ]]; then
|
||||
# Domain not found in the whitelist file, add it!
|
||||
if [[ "${verbose}" == true ]]; then
|
||||
echo "::: Adding $1 to $list..."
|
||||
fi
|
||||
reload=true
|
||||
# Add it to the list we want to add it to
|
||||
echo "$1" >> "${list}"
|
||||
else
|
||||
if [[ "${verbose}" == true ]]; then
|
||||
echo "::: ${1} already exists in ${list}, no need to add!"
|
||||
fi
|
||||
fi
|
||||
elif [[ "${list}" == "${wildcardlist}" ]]; then
|
||||
source "${piholeDir}/setupVars.conf"
|
||||
# Remove the /* from the end of the IPv4addr.
|
||||
IPV4_ADDRESS=${IPV4_ADDRESS%/*}
|
||||
IPV6_ADDRESS=${IPV6_ADDRESS}
|
||||
|
||||
bool=true
|
||||
# Is the domain in the list?
|
||||
grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false
|
||||
|
||||
if [[ "${bool}" == false ]]; then
|
||||
if [[ "${verbose}" == true ]]; then
|
||||
echo "::: Adding $1 to wildcard blacklist..."
|
||||
fi
|
||||
reload=true
|
||||
echo "address=/$1/${IPV4_ADDRESS}" >> "${wildcardlist}"
|
||||
if [[ "${#IPV6_ADDRESS}" > 0 ]]; then
|
||||
echo "address=/$1/${IPV6_ADDRESS}" >> "${wildcardlist}"
|
||||
fi
|
||||
else
|
||||
if [[ "${verbose}" == true ]]; then
|
||||
echo "::: ${1} already exists in wildcard blacklist, no need to add!"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
RemoveDomain() {
|
||||
list="$2"
|
||||
domain=$(EscapeRegexp "$1")
|
||||
|
||||
if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then
|
||||
bool=true
|
||||
# Is it in the list? Logic follows that if its whitelisted it should not be blacklisted and vice versa
|
||||
grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false
|
||||
if [[ "${bool}" == true ]]; then
|
||||
# Remove it from the other one
|
||||
echo "::: Removing $1 from $list..."
|
||||
# /I flag: search case-insensitive
|
||||
sed -i "/${domain}/Id" "${list}"
|
||||
reload=true
|
||||
else
|
||||
if [[ "${verbose}" == true ]]; then
|
||||
echo "::: ${1} does not exist in ${list}, no need to remove!"
|
||||
fi
|
||||
fi
|
||||
elif [[ "${list}" == "${wildcardlist}" ]]; then
|
||||
bool=true
|
||||
# Is it in the list?
|
||||
grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false
|
||||
if [[ "${bool}" == true ]]; then
|
||||
# Remove it from the other one
|
||||
echo "::: Removing $1 from $list..."
|
||||
# /I flag: search case-insensitive
|
||||
sed -i "/address=\/${domain}/Id" "${list}"
|
||||
reload=true
|
||||
else
|
||||
if [[ "${verbose}" == true ]]; then
|
||||
echo "::: ${1} does not exist in ${list}, no need to remove!"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
Reload() {
|
||||
# Reload hosts file
|
||||
pihole -g -sd
|
||||
}
|
||||
|
||||
Displaylist() {
|
||||
if [[ "${listMain}" == "${whitelist}" ]]; then
|
||||
string="gravity resistant domains"
|
||||
else
|
||||
string="domains caught in the sinkhole"
|
||||
fi
|
||||
verbose=false
|
||||
echo -e "Displaying $string:\n"
|
||||
count=1
|
||||
while IFS= read -r RD; do
|
||||
echo "${count}: ${RD}"
|
||||
count=$((count+1))
|
||||
done < "${listMain}"
|
||||
exit 0;
|
||||
}
|
||||
|
||||
for var in "$@"; do
|
||||
case "${var}" in
|
||||
"-w" | "whitelist" ) listMain="${whitelist}"; listAlt="${blacklist}";;
|
||||
"-b" | "blacklist" ) listMain="${blacklist}"; listAlt="${whitelist}";;
|
||||
"-wild" | "wildcard" ) listMain="${wildcardlist}";;
|
||||
"-nr"| "--noreload" ) reload=false;;
|
||||
"-d" | "--delmode" ) addmode=false;;
|
||||
"-f" | "--force" ) force=true;;
|
||||
"-q" | "--quiet" ) verbose=false;;
|
||||
"-h" | "--help" ) helpFunc;;
|
||||
"-l" | "--list" ) Displaylist;;
|
||||
* ) HandleOther "${var}";;
|
||||
esac
|
||||
done
|
||||
|
||||
shift
|
||||
|
||||
if [[ $# = 0 ]]; then
|
||||
helpFunc
|
||||
fi
|
||||
|
||||
PoplistFile
|
||||
|
||||
if ${reload}; then
|
||||
Reload
|
||||
fi
|
206
advanced/Scripts/piholeCheckout.sh
Normal file
206
advanced/Scripts/piholeCheckout.sh
Normal file
@@ -0,0 +1,206 @@
|
||||
#!/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.
|
||||
#
|
||||
# Switch Pi-hole subsystems to a different Github branch
|
||||
#
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
|
||||
PH_TEST="true" source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
|
||||
|
||||
# webInterfaceGitUrl set in basic-install.sh
|
||||
# webInterfaceDir set in basic-install.sh
|
||||
# piholeGitURL set in basic-install.sh
|
||||
# is_repo() sourced from basic-install.sh
|
||||
# setupVars set in basic-install.sh
|
||||
|
||||
source "${setupVars}"
|
||||
update="false"
|
||||
|
||||
# Colour codes
|
||||
red="\e[1;31m"
|
||||
def="\e[0m"
|
||||
|
||||
fully_fetch_repo() {
|
||||
# Add upstream branches to shallow clone
|
||||
local directory="${1}"
|
||||
|
||||
cd "${directory}" || return 1
|
||||
if is_repo "${directory}"; then
|
||||
git remote set-branches origin '*' || return 1
|
||||
git fetch --quiet || return 1
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
get_available_branches() {
|
||||
# Return available branches
|
||||
local directory="${1}"
|
||||
|
||||
cd "${directory}" || return 1
|
||||
# Get reachable remote branches
|
||||
git remote show origin | grep 'tracked' | sed 's/tracked//;s/ //g'
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
fetch_checkout_pull_branch() {
|
||||
# Check out specified branch
|
||||
local directory="${1}"
|
||||
local branch="${2}"
|
||||
|
||||
# Set the reference for the requested branch, fetch, check it put and pull it
|
||||
cd "${directory}"
|
||||
git remote set-branches origin "${branch}" || return 1
|
||||
git stash --all --quiet &> /dev/null || true
|
||||
git clean --force -d || true
|
||||
git fetch --quiet || return 1
|
||||
checkout_pull_branch "${directory}" "${branch}" || return 1
|
||||
}
|
||||
|
||||
checkout_pull_branch() {
|
||||
# Check out specified branch
|
||||
local directory="${1}"
|
||||
local branch="${2}"
|
||||
local oldbranch
|
||||
|
||||
cd "${directory}" || return 1
|
||||
|
||||
oldbranch="$(git symbolic-ref HEAD)"
|
||||
|
||||
git checkout "${branch}" || return 1
|
||||
|
||||
if [ "$(git diff "${oldbranch}" | grep -c "^")" -gt "0" ]; then
|
||||
update="true"
|
||||
fi
|
||||
|
||||
git pull || return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
warning1() {
|
||||
echo " Please note that changing branches severely alters your Pi-hole subsystems"
|
||||
echo " Features that work on the master branch, may not on a development branch"
|
||||
echo -e " ${red}This feature is NOT supported unless a Pi-hole developer explicitly asks!${def}"
|
||||
read -r -p " Have you read and understood this? [y/N] " response
|
||||
case ${response} in
|
||||
[yY][eE][sS]|[yY])
|
||||
echo "::: Continuing with branch change."
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
echo "::: Branch change has been cancelled."
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
checkout() {
|
||||
local corebranches
|
||||
local webbranches
|
||||
|
||||
# Avoid globbing
|
||||
set -f
|
||||
|
||||
#This is unlikely
|
||||
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
|
||||
echo "::: Critical Error: Core Pi-hole repo is missing from system!"
|
||||
echo "::: Please re-run install script from https://github.com/pi-hole/pi-hole"
|
||||
exit 1;
|
||||
fi
|
||||
if [[ ${INSTALL_WEB} == "true" ]]; then
|
||||
if ! is_repo "${webInterfaceDir}" ; then
|
||||
echo "::: Critical Error: Web Admin repo is missing from system!"
|
||||
echo "::: Please re-run install script from https://github.com/pi-hole/pi-hole"
|
||||
exit 1;
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z "${1}" ]]; then
|
||||
echo "::: No option detected. Please use 'pihole checkout <master|dev>'."
|
||||
echo "::: Or enter the repository and branch you would like to check out:"
|
||||
echo "::: 'pihole checkout <web|core> <branchname>'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! warning1 ; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${1}" == "dev" ]] ; then
|
||||
# Shortcut to check out development branches
|
||||
echo "::: Shortcut \"dev\" detected - checking out development / devel branches ..."
|
||||
echo "::: Pi-hole core"
|
||||
fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "development" || { echo "Unable to pull Core developement branch"; exit 1; }
|
||||
if [[ ${INSTALL_WEB} == "true" ]]; then
|
||||
echo "::: Web interface"
|
||||
fetch_checkout_pull_branch "${webInterfaceDir}" "devel" || { echo "Unable to pull Web development branch"; exit 1; }
|
||||
fi
|
||||
echo "::: done!"
|
||||
elif [[ "${1}" == "master" ]] ; then
|
||||
# Shortcut to check out master branches
|
||||
echo "::: Shortcut \"master\" detected - checking out master branches ..."
|
||||
echo "::: Pi-hole core"
|
||||
fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "master" || { echo "Unable to pull Core master branch"; exit 1; }
|
||||
if [[ ${INSTALL_WEB} == "true" ]]; then
|
||||
echo "::: Web interface"
|
||||
fetch_checkout_pull_branch "${webInterfaceDir}" "master" || { echo "Unable to pull web master branch"; exit 1; }
|
||||
fi
|
||||
echo "::: done!"
|
||||
elif [[ "${1}" == "core" ]] ; then
|
||||
echo -n "::: Fetching remote branches for Pi-hole core from ${piholeGitUrl} ... "
|
||||
if ! fully_fetch_repo "${PI_HOLE_FILES_DIR}" ; then
|
||||
echo "::: Fetching all branches for Pi-hole core repo failed!"
|
||||
exit 1
|
||||
fi
|
||||
corebranches=($(get_available_branches "${PI_HOLE_FILES_DIR}"))
|
||||
echo " done!"
|
||||
echo "::: ${#corebranches[@]} branches available"
|
||||
echo ":::"
|
||||
# Have to user chosing the branch he wants
|
||||
if ! (for e in "${corebranches[@]}"; do [[ "$e" == "${2}" ]] && exit 0; done); then
|
||||
echo "::: Requested branch \"${2}\" is not available!"
|
||||
echo "::: Available branches for core are:"
|
||||
for e in "${corebranches[@]}"; do echo "::: $e"; done
|
||||
exit 1
|
||||
fi
|
||||
checkout_pull_branch "${PI_HOLE_FILES_DIR}" "${2}"
|
||||
elif [[ "${1}" == "web" && "${INSTALL_WEB}" == "true" ]] ; then
|
||||
echo -n "::: Fetching remote branches for the web interface from ${webInterfaceGitUrl} ... "
|
||||
if ! fully_fetch_repo "${webInterfaceDir}" ; then
|
||||
echo "::: Fetching all branches for Pi-hole web interface repo failed!"
|
||||
exit 1
|
||||
fi
|
||||
webbranches=($(get_available_branches "${webInterfaceDir}"))
|
||||
echo " done!"
|
||||
echo "::: ${#webbranches[@]} branches available"
|
||||
echo ":::"
|
||||
# Have to user chosing the branch he wants
|
||||
if ! (for e in "${webbranches[@]}"; do [[ "$e" == "${2}" ]] && exit 0; done); then
|
||||
echo "::: Requested branch \"${2}\" is not available!"
|
||||
echo "::: Available branches for web are:"
|
||||
for e in "${webbranches[@]}"; do echo "::: $e"; done
|
||||
exit 1
|
||||
fi
|
||||
checkout_pull_branch "${webInterfaceDir}" "${2}"
|
||||
else
|
||||
echo "::: Requested option \"${1}\" is not available!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Force updating everything
|
||||
if [[ ! "${1}" == "web" && "${update}" == "true" ]]; then
|
||||
echo "::: Running installer to upgrade your installation"
|
||||
if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then
|
||||
exit 0
|
||||
else
|
||||
echo "Unable to complete update, contact Pi-hole"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
542
advanced/Scripts/piholeDebug.sh
Executable file
542
advanced/Scripts/piholeDebug.sh
Executable file
@@ -0,0 +1,542 @@
|
||||
#!/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.
|
||||
#
|
||||
# Generates pihole_debug.log to be used for troubleshooting.
|
||||
#
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
|
||||
|
||||
set -o pipefail
|
||||
|
||||
######## GLOBAL VARS ########
|
||||
VARSFILE="/etc/pihole/setupVars.conf"
|
||||
DEBUG_LOG="/var/log/pihole_debug.log"
|
||||
DNSMASQFILE="/etc/dnsmasq.conf"
|
||||
DNSMASQCONFDIR="/etc/dnsmasq.d/*"
|
||||
LIGHTTPDFILE="/etc/lighttpd/lighttpd.conf"
|
||||
LIGHTTPDERRFILE="/var/log/lighttpd/error.log"
|
||||
GRAVITYFILE="/etc/pihole/gravity.list"
|
||||
WHITELISTFILE="/etc/pihole/whitelist.txt"
|
||||
BLACKLISTFILE="/etc/pihole/blacklist.txt"
|
||||
ADLISTFILE="/etc/pihole/adlists.list"
|
||||
PIHOLELOG="/var/log/pihole.log"
|
||||
PIHOLEGITDIR="/etc/.pihole/"
|
||||
ADMINGITDIR="/var/www/html/admin/"
|
||||
WHITELISTMATCHES="/tmp/whitelistmatches.list"
|
||||
readonly FTLLOG="/var/log/pihole-FTL.log"
|
||||
|
||||
TIMEOUT=60
|
||||
# Header info and introduction
|
||||
cat << EOM
|
||||
::: Beginning Pi-hole debug at $(date)!
|
||||
:::
|
||||
::: This process collects information from your Pi-hole, and optionally uploads
|
||||
::: it to a unique and random directory on tricorder.pi-hole.net.
|
||||
:::
|
||||
::: NOTE: All log files auto-delete after 48 hours and ONLY the Pi-hole developers
|
||||
::: can access your data via the given token. We have taken these extra steps to
|
||||
::: secure your data and will work to further reduce any personal information gathered.
|
||||
:::
|
||||
::: Please read and note any issues, and follow any directions advised during this process.
|
||||
EOM
|
||||
|
||||
source ${VARSFILE}
|
||||
|
||||
### Private functions exist here ###
|
||||
log_write() {
|
||||
echo "${@}" >&3
|
||||
}
|
||||
|
||||
log_echo() {
|
||||
case ${1} in
|
||||
-n)
|
||||
echo -n "::: ${2}"
|
||||
log_write "${2}"
|
||||
;;
|
||||
-r)
|
||||
echo "::: ${2}"
|
||||
log_write "${2}"
|
||||
;;
|
||||
-l)
|
||||
echo "${2}"
|
||||
log_write "${2}"
|
||||
;;
|
||||
*)
|
||||
echo "::: ${1}"
|
||||
log_write "${1}"
|
||||
esac
|
||||
}
|
||||
|
||||
header_write() {
|
||||
log_echo ""
|
||||
log_echo "---= ${1}"
|
||||
log_write ""
|
||||
}
|
||||
|
||||
file_parse() {
|
||||
while read -r line; do
|
||||
if [ ! -z "${line}" ]; then
|
||||
[[ "${line}" =~ ^#.*$ || ! "${line}" || "${line}" == "WEBPASSWORD="* ]] && continue
|
||||
log_write "${line}"
|
||||
fi
|
||||
done < "${1}"
|
||||
log_write ""
|
||||
}
|
||||
|
||||
block_parse() {
|
||||
log_write "${1}"
|
||||
}
|
||||
|
||||
lsof_parse() {
|
||||
local user
|
||||
local process
|
||||
|
||||
user=$(echo ${1} | cut -f 3 -d ' ' | cut -c 2-)
|
||||
process=$(echo ${1} | cut -f 2 -d ' ' | cut -c 2-)
|
||||
[[ ${2} -eq ${process} ]] \
|
||||
&& echo "::: Correctly configured." \
|
||||
|| log_echo "::: Failure: Incorrectly configured daemon."
|
||||
|
||||
log_write "Found user ${user} with process ${process}"
|
||||
}
|
||||
|
||||
|
||||
version_check() {
|
||||
header_write "Detecting Installed Package Versions:"
|
||||
|
||||
local error_found
|
||||
local pi_hole_ver
|
||||
local pi_hole_branch
|
||||
local pi_hole_commit
|
||||
local admin_ver
|
||||
local admin_branch
|
||||
local admin_commit
|
||||
local light_ver
|
||||
local php_ver
|
||||
local status
|
||||
error_found=0
|
||||
|
||||
cd "${PIHOLEGITDIR}" &> /dev/null || \
|
||||
{ status="Pi-hole git directory not found."; error_found=1; }
|
||||
if git status &> /dev/null; then
|
||||
pi_hole_ver=$(git describe --tags --abbrev=0)
|
||||
pi_hole_branch=$(git rev-parse --abbrev-ref HEAD)
|
||||
pi_hole_commit=$(git describe --long --dirty --tags --always)
|
||||
log_echo -r "Pi-hole: ${pi_hole_ver:-Untagged} (${pi_hole_branch:-Detached}:${pi_hole_commit})"
|
||||
else
|
||||
status=${status:-"Pi-hole repository damaged."}
|
||||
error_found=1
|
||||
fi
|
||||
if [[ "${status}" ]]; then
|
||||
log_echo "${status}"
|
||||
unset status
|
||||
fi
|
||||
|
||||
cd "${ADMINGITDIR}" || \
|
||||
{ status="Pi-hole Dashboard git directory not found."; error_found=1; }
|
||||
if git status &> /dev/null; then
|
||||
admin_ver=$(git describe --tags --abbrev=0)
|
||||
admin_branch=$(git rev-parse --abbrev-ref HEAD)
|
||||
admin_commit=$(git describe --long --dirty --tags --always)
|
||||
log_echo -r "Pi-hole Dashboard: ${admin_ver:-Untagged} (${admin_branch:-Detached}:${admin_commit})"
|
||||
else
|
||||
status=${status:-"Pi-hole Dashboard repository damaged."}
|
||||
error_found=1
|
||||
fi
|
||||
if [[ "${status}" ]]; then
|
||||
log_echo "${status}"
|
||||
unset status
|
||||
fi
|
||||
|
||||
if light_ver=$(lighttpd -v |& head -n1 | cut -d " " -f1); then
|
||||
log_echo -r "${light_ver}"
|
||||
else
|
||||
log_echo "lighttpd not installed."
|
||||
error_found=1
|
||||
fi
|
||||
if php_ver=$(php -v |& head -n1); then
|
||||
log_echo -r "${php_ver}"
|
||||
else
|
||||
log_echo "PHP not installed."
|
||||
error_found=1
|
||||
fi
|
||||
|
||||
return "${error_found}"
|
||||
}
|
||||
|
||||
dir_check() {
|
||||
header_write "Detecting contents of ${1}:"
|
||||
for file in $1*; do
|
||||
header_write "File ${file} found"
|
||||
echo -n "::: Parsing..."
|
||||
file_parse "${file}"
|
||||
echo "done"
|
||||
done
|
||||
echo ":::"
|
||||
}
|
||||
|
||||
files_check() {
|
||||
#Check non-zero length existence of ${1}
|
||||
header_write "Detecting existence of ${1}:"
|
||||
local search_file="${1}"
|
||||
if [[ -s ${search_file} ]]; then
|
||||
echo -n "::: File exists, parsing..."
|
||||
file_parse "${search_file}"
|
||||
echo "done"
|
||||
return 0
|
||||
else
|
||||
log_echo "${1} not found!"
|
||||
return 1
|
||||
fi
|
||||
echo ":::"
|
||||
}
|
||||
|
||||
source_file() {
|
||||
local file_found=$(files_check "${1}") \
|
||||
&& (source "${1}" &> /dev/null && echo "${file_found} and was successfully sourced") \
|
||||
|| log_echo -l "${file_found} and could not be sourced"
|
||||
}
|
||||
|
||||
distro_check() {
|
||||
local soft_fail
|
||||
header_write "Detecting installed OS Distribution"
|
||||
soft_fail=0
|
||||
local distro="$(cat /etc/*release)" && block_parse "${distro}" || (log_echo "Distribution details not found." && soft_fail=1)
|
||||
return "${soft_fail}"
|
||||
}
|
||||
|
||||
processor_check() {
|
||||
header_write "Checking processor variety"
|
||||
log_write $(uname -m) && return 0 || return 1
|
||||
}
|
||||
|
||||
ipv6_check() {
|
||||
# Check if system is IPv6 enabled, for use in other functions
|
||||
if [[ $IPV6_ADDRESS ]]; then
|
||||
ls /proc/net/if_inet6 &>/dev/null
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
ip_check() {
|
||||
local protocol=${1}
|
||||
local gravity=${2}
|
||||
header_write "Checking IPv${protocol} Stack"
|
||||
|
||||
local ip_addr_list="$(ip -${protocol} addr show dev ${PIHOLE_INTERFACE} | awk -F ' ' '{ for(i=1;i<=NF;i++) if ($i ~ '/^inet/') print $(i+1) }')"
|
||||
if [[ -n ${ip_addr_list} ]]; then
|
||||
log_write "IPv${protocol} on ${PIHOLE_INTERFACE}"
|
||||
log_write "Gravity configured for: ${2:-NOT CONFIGURED}"
|
||||
log_write "----"
|
||||
log_write "${ip_addr_list}"
|
||||
echo "::: IPv${protocol} addresses located on ${PIHOLE_INTERFACE}"
|
||||
ip_ping_check ${protocol}
|
||||
return $(( 0 + $? ))
|
||||
else
|
||||
log_echo "No IPv${protocol} found on ${PIHOLE_INTERFACE}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
ip_ping_check() {
|
||||
local protocol=${1}
|
||||
local cmd
|
||||
|
||||
if [[ ${protocol} == "6" ]]; then
|
||||
cmd="ping6"
|
||||
g_addr="2001:4860:4860::8888"
|
||||
else
|
||||
cmd="ping"
|
||||
g_addr="8.8.8.8"
|
||||
fi
|
||||
|
||||
local ip_def_gateway=$(ip -${protocol} route | grep default | cut -d ' ' -f 3)
|
||||
if [[ -n ${ip_def_gateway} ]]; then
|
||||
echo -n "::: Pinging default IPv${protocol} gateway: "
|
||||
if ! ping_gateway="$(${cmd} -q -W 3 -c 3 -n ${ip_def_gateway} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then
|
||||
log_echo "Gateway did not respond."
|
||||
return 1
|
||||
else
|
||||
log_echo "Gateway responded."
|
||||
log_write "${ping_gateway}"
|
||||
fi
|
||||
echo -n "::: Pinging Internet via IPv${protocol}: "
|
||||
if ! ping_inet="$(${cmd} -q -W 3 -c 3 -n ${g_addr} -I ${PIHOLE_INTERFACE} | tail -n 3)"; then
|
||||
log_echo "Query did not respond."
|
||||
return 1
|
||||
else
|
||||
log_echo "Query responded."
|
||||
log_write "${ping_inet}"
|
||||
fi
|
||||
else
|
||||
log_echo " No gateway detected."
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
port_check() {
|
||||
local lsof_value
|
||||
|
||||
lsof_value=$(lsof -i ${1}:${2} -FcL | tr '\n' ' ') \
|
||||
&& lsof_parse "${lsof_value}" "${3}" \
|
||||
|| log_echo "Failure: IPv${1} Port not in use"
|
||||
}
|
||||
|
||||
daemon_check() {
|
||||
# Check for daemon ${1} on port ${2}
|
||||
header_write "Daemon Process Information"
|
||||
|
||||
echo "::: Checking ${2} port for ${1} listener."
|
||||
|
||||
if [[ ${IPV6_READY} ]]; then
|
||||
port_check 6 "${2}" "${1}"
|
||||
fi
|
||||
lsof_value=$(lsof -i 4:${2} -FcL | tr '\n' ' ') \
|
||||
port_check 4 "${2}" "${1}"
|
||||
}
|
||||
|
||||
testResolver() {
|
||||
local protocol="${1}"
|
||||
header_write "Resolver Functions Check (IPv${protocol})"
|
||||
local IP="${2}"
|
||||
local g_addr
|
||||
local l_addr
|
||||
local url
|
||||
local testurl
|
||||
local localdig
|
||||
local piholedig
|
||||
local remotedig
|
||||
|
||||
if [[ ${protocol} == "6" ]]; then
|
||||
g_addr="2001:4860:4860::8888"
|
||||
l_addr="::1"
|
||||
r_type="AAAA"
|
||||
else
|
||||
g_addr="8.8.8.8"
|
||||
l_addr="127.0.0.1"
|
||||
r_type="A"
|
||||
fi
|
||||
|
||||
# Find a blocked url that has not been whitelisted.
|
||||
url=$(shuf -n 1 "${GRAVITYFILE}" | awk -F ' ' '{ print $2 }')
|
||||
|
||||
testurl="${url:-doubleclick.com}"
|
||||
|
||||
|
||||
log_write "Resolution of ${testurl} from Pi-hole (${l_addr}):"
|
||||
if localdig=$(dig -"${protocol}" "${testurl}" @${l_addr} +short "${r_type}"); then
|
||||
log_write "${localdig}"
|
||||
else
|
||||
log_write "Failed to resolve ${testurl} on Pi-hole (${l_addr})"
|
||||
fi
|
||||
log_write ""
|
||||
|
||||
log_write "Resolution of ${testurl} from Pi-hole (${IP}):"
|
||||
if piholedig=$(dig -"${protocol}" "${testurl}" @"${IP}" +short "${r_type}"); then
|
||||
log_write "${piholedig}"
|
||||
else
|
||||
log_write "Failed to resolve ${testurl} on Pi-hole (${IP})"
|
||||
fi
|
||||
log_write ""
|
||||
|
||||
|
||||
log_write "Resolution of ${testurl} from ${g_addr}:"
|
||||
if remotedig=$(dig -"${protocol}" "${testurl}" @${g_addr} +short "${r_type}"); then
|
||||
log_write "${remotedig:-NXDOMAIN}"
|
||||
else
|
||||
log_write "Failed to resolve ${testurl} on upstream server ${g_addr}"
|
||||
fi
|
||||
log_write ""
|
||||
}
|
||||
|
||||
testChaos(){
|
||||
# Check Pi-hole specific records
|
||||
|
||||
log_write "Pi-hole dnsmasq specific records lookups"
|
||||
log_write "Cache Size:"
|
||||
log_write $(dig +short chaos txt cachesize.bind)
|
||||
log_write "Upstream Servers:"
|
||||
log_write $(dig +short chaos txt servers.bind)
|
||||
log_write ""
|
||||
|
||||
}
|
||||
checkProcesses() {
|
||||
header_write "Processes Check"
|
||||
|
||||
echo "::: Logging status of lighttpd, dnsmasq and pihole-FTL..."
|
||||
PROCESSES=( lighttpd dnsmasq pihole-FTL )
|
||||
for i in "${PROCESSES[@]}"; do
|
||||
log_write "Status for ${i} daemon:"
|
||||
log_write $(systemctl is-active "${i}")
|
||||
done
|
||||
log_write ""
|
||||
}
|
||||
|
||||
debugLighttpd() {
|
||||
echo "::: Checking for necessary lighttpd files."
|
||||
files_check "${LIGHTTPDFILE}"
|
||||
files_check "${LIGHTTPDERRFILE}"
|
||||
echo ":::"
|
||||
}
|
||||
|
||||
countdown() {
|
||||
local tuvix
|
||||
tuvix=${TIMEOUT}
|
||||
printf "::: Logging will automatically teminate in %s seconds\n" "${TIMEOUT}"
|
||||
while [ $tuvix -ge 1 ]
|
||||
do
|
||||
printf ":::\t%s seconds left. " "${tuvix}"
|
||||
if [[ -z "${WEBCALL}" ]]; then
|
||||
printf "\r"
|
||||
else
|
||||
printf "\n"
|
||||
fi
|
||||
sleep 5
|
||||
tuvix=$(( tuvix - 5 ))
|
||||
done
|
||||
}
|
||||
|
||||
# Continuously append the pihole.log file to the pihole_debug.log file
|
||||
dumpPiHoleLog() {
|
||||
trap '{ echo -e "\n::: Finishing debug write from interrupt... Quitting!" ; exit 1; }' INT
|
||||
echo "::: "
|
||||
echo "::: --= User Action Required =--"
|
||||
echo -e "::: Try loading a site that you are having trouble with now from a client web browser.. \n:::\t(Press CTRL+C to finish logging.)"
|
||||
header_write "pihole.log"
|
||||
if [ -e "${PIHOLELOG}" ]; then
|
||||
# Dummy process to use for flagging down tail to terminate
|
||||
countdown &
|
||||
tail -n0 -f --pid=$! "${PIHOLELOG}" >&4
|
||||
else
|
||||
log_write "No pihole.log file found!"
|
||||
printf ":::\tNo pihole.log file found!\n"
|
||||
fi
|
||||
}
|
||||
|
||||
# Anything to be done after capturing of pihole.log terminates
|
||||
finalWork() {
|
||||
local tricorder
|
||||
echo "::: Finshed debugging!"
|
||||
|
||||
# Ensure the file exists, create if not, clear if exists.
|
||||
truncate --size=0 "${DEBUG_LOG}"
|
||||
chmod 644 ${DEBUG_LOG}
|
||||
chown "$USER":pihole ${DEBUG_LOG}
|
||||
# copy working temp file to final log location
|
||||
cat /proc/$$/fd/3 >> "${DEBUG_LOG}"
|
||||
# Straight dump of tailing the logs, can sanitize later if needed.
|
||||
cat /proc/$$/fd/4 >> "${DEBUG_LOG}"
|
||||
|
||||
echo "::: The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only."
|
||||
if [[ "${AUTOMATED}" ]]; then
|
||||
echo "::: Debug script running in automated mode, uploading log to tricorder..."
|
||||
tricorder=$(cat /var/log/pihole_debug.log | nc tricorder.pi-hole.net 9999)
|
||||
else
|
||||
read -r -p "::: Would you like to upload the log? [y/N] " response
|
||||
case ${response} in
|
||||
[yY][eE][sS]|[yY])
|
||||
tricorder=$(cat /var/log/pihole_debug.log | nc tricorder.pi-hole.net 9999)
|
||||
;;
|
||||
*)
|
||||
echo "::: Log will NOT be uploaded to tricorder."
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
# Check if tricorder.pi-hole.net is reachable and provide token.
|
||||
if [ -n "${tricorder}" ]; then
|
||||
echo "::: ---=== Your debug token is : ${tricorder} Please make a note of it. ===---"
|
||||
echo "::: Contact the Pi-hole team with your token for assistance."
|
||||
echo "::: Thank you."
|
||||
else
|
||||
echo "::: There was an error uploading your debug log."
|
||||
echo "::: Please try again or contact the Pi-hole team for assistance."
|
||||
fi
|
||||
echo "::: A local copy of the Debug log can be found at : /var/log/pihole_debug.log"
|
||||
}
|
||||
|
||||
### END FUNCTIONS ###
|
||||
# Create temporary file for log
|
||||
TEMPLOG=$(mktemp /tmp/pihole_temp.XXXXXX)
|
||||
# Open handle 3 for templog
|
||||
exec 3>"$TEMPLOG"
|
||||
# Delete templog, but allow for addressing via file handle.
|
||||
rm "$TEMPLOG"
|
||||
|
||||
# Create temporary file for logdump using file handle 4
|
||||
DUMPLOG=$(mktemp /tmp/pihole_temp.XXXXXX)
|
||||
exec 4>"$DUMPLOG"
|
||||
rm "$DUMPLOG"
|
||||
|
||||
# Gather version of required packages / repositories
|
||||
version_check || echo "REQUIRED FILES MISSING"
|
||||
# Check for newer setupVars storage file
|
||||
source_file "/etc/pihole/setupVars.conf"
|
||||
# Gather information about the running distribution
|
||||
distro_check || echo "Distro Check soft fail"
|
||||
# Gather processor type
|
||||
processor_check || echo "Processor Check soft fail"
|
||||
|
||||
ip_check 6 ${IPV6_ADDRESS}
|
||||
ip_check 4 ${IPV4_ADDRESS}
|
||||
|
||||
daemon_check lighttpd http
|
||||
daemon_check dnsmasq domain
|
||||
daemon_check pihole-FTL 4711
|
||||
checkProcesses
|
||||
|
||||
# Check local/IP/Google for IPv4 Resolution
|
||||
testResolver 4 "${IPV4_ADDRESS%/*}"
|
||||
# If IPv6 enabled, check resolution
|
||||
if [[ "${IPV6_ADDRESS}" ]]; then
|
||||
testResolver 6 "${IPV6_ADDRESS%/*}"
|
||||
fi
|
||||
# Poll dnsmasq Pi-hole specific queries
|
||||
testChaos
|
||||
|
||||
debugLighttpd
|
||||
|
||||
files_check "${DNSMASQFILE}"
|
||||
dir_check "${DNSMASQCONFDIR}"
|
||||
files_check "${WHITELISTFILE}"
|
||||
files_check "${BLACKLISTFILE}"
|
||||
files_check "${ADLISTFILE}"
|
||||
|
||||
|
||||
header_write "Analyzing gravity.list"
|
||||
|
||||
gravity_length=$(grep -c ^ "${GRAVITYFILE}") \
|
||||
&& log_write "${GRAVITYFILE} is ${gravity_length} lines long." \
|
||||
|| log_echo "Warning: No gravity.list file found!"
|
||||
|
||||
header_write "Analyzing pihole.log"
|
||||
|
||||
pihole_length=$(grep -c ^ "${PIHOLELOG}") \
|
||||
&& log_write "${PIHOLELOG} is ${pihole_length} lines long." \
|
||||
|| log_echo "Warning: No pihole.log file found!"
|
||||
|
||||
pihole_size=$(du -h "${PIHOLELOG}" | awk '{ print $1 }') \
|
||||
&& log_write "${PIHOLELOG} is ${pihole_size}." \
|
||||
|| log_echo "Warning: No pihole.log file found!"
|
||||
|
||||
header_write "Analyzing pihole-FTL.log"
|
||||
|
||||
FTL_length=$(grep -c ^ "${FTLLOG}") \
|
||||
&& log_write "${FTLLOG} is ${FTL_length} lines long." \
|
||||
|| log_echo "Warning: No pihole-FTL.log file found!"
|
||||
|
||||
FTL_size=$(du -h "${FTLLOG}" | awk '{ print $1 }') \
|
||||
&& log_write "${FTLLOG} is ${FTL_size}." \
|
||||
|| log_echo "Warning: No pihole-FTL.log file found!"
|
||||
|
||||
tail -n50 "${FTLLOG}" >&3
|
||||
|
||||
trap finalWork EXIT
|
||||
|
||||
### Method calls for additional logging ###
|
||||
dumpPiHoleLog
|
@@ -1,3 +1,45 @@
|
||||
#!/bin/bash
|
||||
# Flushes /var/log/pihole.log
|
||||
truncate -s 0 /var/log/pihole.log
|
||||
#!/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.
|
||||
#
|
||||
# Flushes Pi-hole's log file
|
||||
#
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
if [[ "$@" != *"quiet"* ]]; then
|
||||
echo -n "::: Flushing /var/log/pihole.log ..."
|
||||
fi
|
||||
if [[ "$@" == *"once"* ]]; then
|
||||
# Nightly logrotation
|
||||
if command -v /usr/sbin/logrotate >/dev/null; then
|
||||
# Logrotate once
|
||||
/usr/sbin/logrotate --force /etc/pihole/logrotate
|
||||
else
|
||||
# Copy pihole.log over to pihole.log.1
|
||||
# and empty out pihole.log
|
||||
# Note that moving the file is not an option, as
|
||||
# dnsmasq would happily continue writing into the
|
||||
# moved file (it will have the same file handler)
|
||||
cp /var/log/pihole.log /var/log/pihole.log.1
|
||||
echo " " > /var/log/pihole.log
|
||||
fi
|
||||
else
|
||||
# Manual flushing
|
||||
if command -v /usr/sbin/logrotate >/dev/null; then
|
||||
# Logrotate twice to move all data out of sight of FTL
|
||||
/usr/sbin/logrotate --force /etc/pihole/logrotate; sleep 3
|
||||
/usr/sbin/logrotate --force /etc/pihole/logrotate
|
||||
else
|
||||
# Flush both pihole.log and pihole.log.1 (if existing)
|
||||
echo " " > /var/log/pihole.log
|
||||
if [ -f /var/log/pihole.log.1 ]; then
|
||||
echo " " > /var/log/pihole.log.1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$@" != *"quiet"* ]]; then
|
||||
echo "... done!"
|
||||
fi
|
||||
|
74
advanced/Scripts/setupLCD.sh
Executable file
74
advanced/Scripts/setupLCD.sh
Executable file
@@ -0,0 +1,74 @@
|
||||
#!/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 "Unrecognised 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:
|
||||
# http://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'
|
225
advanced/Scripts/update.sh
Executable file
225
advanced/Scripts/update.sh
Executable file
@@ -0,0 +1,225 @@
|
||||
#!/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.
|
||||
#
|
||||
# Check Pi-hole core and admin pages versions and determine what
|
||||
# upgrade (if any) is required. Automatically updates and reinstalls
|
||||
# application if update is detected.
|
||||
#
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
|
||||
|
||||
# Variables
|
||||
|
||||
readonly ADMIN_INTERFACE_GIT_URL="https://github.com/pi-hole/AdminLTE.git"
|
||||
readonly ADMIN_INTERFACE_DIR="/var/www/html/admin"
|
||||
readonly PI_HOLE_GIT_URL="https://github.com/pi-hole/pi-hole.git"
|
||||
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
|
||||
|
||||
PH_TEST=true
|
||||
source ${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh
|
||||
|
||||
# is_repo() sourced from basic-install.sh
|
||||
# make_repo() sourced from basic-install.sh
|
||||
# update_repo() source from basic-install.sh
|
||||
# getGitFiles() sourced from basic-install.sh
|
||||
|
||||
GitCheckUpdateAvail() {
|
||||
local directory="${1}"
|
||||
curdir=$PWD
|
||||
cd "${directory}"
|
||||
|
||||
# Fetch latest changes in this repo
|
||||
git fetch --quiet origin
|
||||
|
||||
# @ alone is a shortcut for HEAD. Older versions of git
|
||||
# need @{0}
|
||||
LOCAL="$(git rev-parse @{0})"
|
||||
|
||||
# The suffix @{upstream} to a branchname
|
||||
# (short form <branchname>@{u}) refers
|
||||
# to the branch that the branch specified
|
||||
# by branchname is set to build on top of#
|
||||
# (configured with branch.<name>.remote and
|
||||
# branch.<name>.merge). A missing branchname
|
||||
# defaults to the current one.
|
||||
REMOTE="$(git rev-parse @{upstream})"
|
||||
|
||||
if [[ ${#LOCAL} == 0 ]]; then
|
||||
echo "::: Error: Local revision could not be obtained, ask Pi-hole support."
|
||||
echo "::: Additional debugging output:"
|
||||
git status
|
||||
exit
|
||||
fi
|
||||
if [[ ${#REMOTE} == 0 ]]; then
|
||||
echo "::: Error: Remote revision could not be obtained, ask Pi-hole support."
|
||||
echo "::: Additional debugging output:"
|
||||
git status
|
||||
exit
|
||||
fi
|
||||
|
||||
# Change back to original directory
|
||||
cd "${curdir}"
|
||||
|
||||
if [[ "${LOCAL}" != "${REMOTE}" ]]; then
|
||||
# Local branch is behind remote branch -> Update
|
||||
return 0
|
||||
else
|
||||
# Local branch is up-to-date or in a situation
|
||||
# where this updater cannot be used (like on a
|
||||
# branch that exists only locally)
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
FTLcheckUpdate() {
|
||||
|
||||
local FTLversion=$(/usr/bin/pihole-FTL tag)
|
||||
local FTLlatesttag=$(curl -sI https://github.com/pi-hole/FTL/releases/latest | grep 'Location' | awk -F '/' '{print $NF}' | tr -d '\r\n')
|
||||
|
||||
if [[ "${FTLversion}" != "${FTLlatesttag}" ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
local pihole_version_current
|
||||
local web_version_current
|
||||
source "${setupVars}"
|
||||
|
||||
#This is unlikely
|
||||
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
|
||||
echo "::: Critical Error: Core Pi-hole repo is missing from system!"
|
||||
echo "::: Please re-run install script from https://github.com/pi-hole/pi-hole"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
echo "::: Checking for updates..."
|
||||
|
||||
if GitCheckUpdateAvail "${PI_HOLE_FILES_DIR}" ; then
|
||||
core_update=true
|
||||
echo "::: Pi-hole Core: update available"
|
||||
else
|
||||
core_update=false
|
||||
echo "::: Pi-hole Core: up to date"
|
||||
fi
|
||||
|
||||
if FTLcheckUpdate ; then
|
||||
FTL_update=true
|
||||
echo "::: FTL: update available"
|
||||
else
|
||||
FTL_update=false
|
||||
echo "::: FTL: up to date"
|
||||
fi
|
||||
|
||||
# Logic: Don't update FTL when there is a core update available
|
||||
# since the core update will run the installer which will itself
|
||||
# re-install (i.e. update) FTL
|
||||
if ${FTL_update} && ! ${core_update}; then
|
||||
echo ":::"
|
||||
echo "::: FTL out of date"
|
||||
FTLdetect
|
||||
echo ":::"
|
||||
fi
|
||||
|
||||
if [[ ${INSTALL_WEB} == true ]]; then
|
||||
if ! is_repo "${ADMIN_INTERFACE_DIR}" ; then
|
||||
echo "::: Critical Error: Web Admin repo is missing from system!"
|
||||
echo "::: Please re-run install script from https://github.com/pi-hole/pi-hole"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
if GitCheckUpdateAvail "${ADMIN_INTERFACE_DIR}" ; then
|
||||
web_update=true
|
||||
echo "::: Web Interface: update available"
|
||||
else
|
||||
web_update=false
|
||||
echo "::: Web Interface: up to date"
|
||||
fi
|
||||
|
||||
# Logic
|
||||
# If Core up to date AND web up to date:
|
||||
# Do nothing
|
||||
# If Core up to date AND web NOT up to date:
|
||||
# Pull web repo
|
||||
# If Core NOT up to date AND web up to date:
|
||||
# pull pihole repo, run install --unattended -- reconfigure
|
||||
# if Core NOT up to date AND web NOT up to date:
|
||||
# pull pihole repo run install --unattended
|
||||
|
||||
if ! ${core_update} && ! ${web_update} ; then
|
||||
if ! ${FTL_update} ; then
|
||||
echo ":::"
|
||||
echo "::: Everything is up to date!"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
elif ! ${core_update} && ${web_update} ; then
|
||||
echo ":::"
|
||||
echo "::: Pi-hole Web Admin files out of date"
|
||||
getGitFiles "${ADMIN_INTERFACE_DIR}" "${ADMIN_INTERFACE_GIT_URL}"
|
||||
|
||||
elif ${core_update} && ! ${web_update} ; then
|
||||
echo ":::"
|
||||
echo "::: Pi-hole core files out of date"
|
||||
getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}"
|
||||
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || echo "Unable to complete update, contact Pi-hole" && exit 1
|
||||
|
||||
elif ${core_update} && ${web_update} ; then
|
||||
echo ":::"
|
||||
echo "::: Updating Pi-hole core and web admin files"
|
||||
getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}"
|
||||
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --unattended || echo "Unable to complete update, contact Pi-hole" && exit 1
|
||||
else
|
||||
echo "*** Update script has malfunctioned, fallthrough reached. Please contact support"
|
||||
exit 1
|
||||
fi
|
||||
else # Web Admin not installed, so only verify if core is up to date
|
||||
if ! ${core_update}; then
|
||||
if ! ${FTL_update} ; then
|
||||
echo ":::"
|
||||
echo "::: Everything is up to date!"
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
echo ":::"
|
||||
echo "::: Pi-hole core files out of date"
|
||||
getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}"
|
||||
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || echo "Unable to complete update, contact Pi-hole" && exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${web_update}" == true ]]; then
|
||||
web_version_current="$(/usr/local/bin/pihole version --admin --current)"
|
||||
echo ":::"
|
||||
echo "::: Web Admin version is now at ${web_version_current/* v/v}}"
|
||||
echo "::: If you had made any changes in '/var/www/html/admin/', they have been stashed using 'git stash'"
|
||||
fi
|
||||
|
||||
if [[ "${core_update}" == true ]]; then
|
||||
pihole_version_current="$(/usr/local/bin/pihole version --pihole --current)"
|
||||
echo ":::"
|
||||
echo "::: Pi-hole version is now at ${pihole_version_current/* v/v}}"
|
||||
echo "::: If you had made any changes in '/etc/.pihole/', they have been stashed using 'git stash'"
|
||||
fi
|
||||
|
||||
if [[ ${FTL_update} == true ]]; then
|
||||
FTL_version_current="$(/usr/local/bin/pihole version --ftl --current)"
|
||||
echo ":::"
|
||||
echo "::: FTL version is now at ${FTL_version_current/* v/v}}"
|
||||
start_service pihole-FTL
|
||||
enable_service pihole-FTL
|
||||
fi
|
||||
|
||||
|
||||
echo ""
|
||||
exit 0
|
||||
|
||||
}
|
||||
|
||||
main
|
168
advanced/Scripts/version.sh
Executable file
168
advanced/Scripts/version.sh
Executable file
@@ -0,0 +1,168 @@
|
||||
#!/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.
|
||||
#
|
||||
# Show version numbers
|
||||
#
|
||||
# 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/"
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
getRemoteVersion(){
|
||||
# Get the version from the remote origin
|
||||
local daemon="${1}"
|
||||
local version
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
versionOutput() {
|
||||
[[ "$1" == "pi-hole" ]] && GITDIR=$COREGITDIR
|
||||
[[ "$1" == "AdminLTE" ]] && GITDIR=$WEBGITDIR
|
||||
[[ "$1" == "FTL" ]] && GITDIR="FTL"
|
||||
|
||||
[[ "$2" == "-c" ]] || [[ "$2" == "--current" ]] || [[ -z "$2" ]] && current=$(getLocalVersion $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")
|
||||
[[ "$3" == "-l" ]] || [[ "$3" == "--latest" ]] || [[ -z "$3" ]] && latHash=$(getRemoteHash "$1" "$(cd "$GITDIR" 2> /dev/null && git rev-parse --abbrev-ref HEAD)")
|
||||
fi
|
||||
|
||||
if [[ -n "$current" ]] && [[ -n "$latest" ]]; then
|
||||
output="${1^} version is $current (Latest: $latest)"
|
||||
elif [[ -n "$current" ]] && [[ -z "$latest" ]]; then
|
||||
output="Current ${1^} version is $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"
|
||||
else
|
||||
errorOutput
|
||||
fi
|
||||
|
||||
[[ -n "$output" ]] && echo " $output"
|
||||
}
|
||||
|
||||
errorOutput() {
|
||||
echo " Invalid Option! Try 'pihole -v --help' for more information."
|
||||
exit 1
|
||||
}
|
||||
|
||||
defaultOutput() {
|
||||
versionOutput "pi-hole" "$@"
|
||||
versionOutput "AdminLTE" "$@"
|
||||
versionOutput "FTL" "$@"
|
||||
}
|
||||
|
||||
helpFunc() {
|
||||
echo "Usage: pihole -v [repo | option] [option]
|
||||
Example: 'pihole -v -p -l'
|
||||
Show Pi-hole, Admin Console & FTL versions
|
||||
|
||||
Repositories:
|
||||
-p, --pihole Only retrieve info regarding Pi-hole repository
|
||||
-a, --admin Only retrieve info regarding AdminLTE repository
|
||||
-f, --ftl Only retrieve info regarding FTL repository
|
||||
|
||||
Options:
|
||||
-c, --current Return the current version
|
||||
-l, --latest Return the latest version
|
||||
--hash Return the Github hash from your local repositories
|
||||
-h, --help Show this help dialog"
|
||||
exit 0
|
||||
}
|
||||
|
||||
case "${1}" in
|
||||
"-p" | "--pihole" ) shift; versionOutput "pi-hole" "$@";;
|
||||
"-a" | "--admin" ) shift; versionOutput "AdminLTE" "$@";;
|
||||
"-f" | "--ftl" ) shift; versionOutput "FTL" "$@";;
|
||||
"-h" | "--help" ) helpFunc;;
|
||||
* ) defaultOutput "$@";;
|
||||
esac
|
465
advanced/Scripts/webpage.sh
Executable file
465
advanced/Scripts/webpage.sh
Executable file
@@ -0,0 +1,465 @@
|
||||
#!/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.
|
||||
#
|
||||
# Web interface settings
|
||||
#
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
readonly setupVars="/etc/pihole/setupVars.conf"
|
||||
readonly dnsmasqconfig="/etc/dnsmasq.d/01-pihole.conf"
|
||||
readonly dhcpconfig="/etc/dnsmasq.d/02-pihole-dhcp.conf"
|
||||
# 03 -> wildcards
|
||||
readonly dhcpstaticconfig="/etc/dnsmasq.d/04-pihole-static-dhcp.conf"
|
||||
|
||||
helpFunc() {
|
||||
echo "Usage: pihole -a [options]
|
||||
Example: pihole -a -p password
|
||||
Set options for the Admin Console
|
||||
|
||||
Options:
|
||||
-f, flush Flush the Pi-hole log
|
||||
-p, password Set Admin Console password
|
||||
-c, celsius Set Celsius as preferred temperature unit
|
||||
-f, fahrenheit Set Fahrenheit as preferred temperature unit
|
||||
-k, kelvin Set Kelvin as preferred temperature unit
|
||||
-h, --help Show this help dialog
|
||||
-i, interface Specify dnsmasq's interface listening behavior
|
||||
Add '-h' for more info on interface usage"
|
||||
exit 0
|
||||
}
|
||||
|
||||
add_setting() {
|
||||
echo "${1}=${2}" >> "${setupVars}"
|
||||
}
|
||||
|
||||
delete_setting() {
|
||||
sed -i "/${1}/d" "${setupVars}"
|
||||
}
|
||||
|
||||
change_setting() {
|
||||
delete_setting "${1}"
|
||||
add_setting "${1}" "${2}"
|
||||
}
|
||||
|
||||
add_dnsmasq_setting() {
|
||||
if [[ "${2}" != "" ]]; then
|
||||
echo "${1}=${2}" >> "${dnsmasqconfig}"
|
||||
else
|
||||
echo "${1}" >> "${dnsmasqconfig}"
|
||||
fi
|
||||
}
|
||||
|
||||
delete_dnsmasq_setting() {
|
||||
sed -i "/${1}/d" "${dnsmasqconfig}"
|
||||
}
|
||||
|
||||
SetTemperatureUnit() {
|
||||
change_setting "TEMPERATUREUNIT" "${unit}"
|
||||
}
|
||||
|
||||
HashPassword() {
|
||||
# Compute password hash twice to avoid rainbow table vulnerability
|
||||
return=$(echo -n ${1} | sha256sum | sed 's/\s.*$//')
|
||||
return=$(echo -n ${return} | sha256sum | sed 's/\s.*$//')
|
||||
echo ${return}
|
||||
}
|
||||
|
||||
SetWebPassword() {
|
||||
if [ "${SUDO_USER}" == "www-data" ]; then
|
||||
echo "Security measure: user www-data is not allowed to change webUI password!"
|
||||
echo "Exiting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "${SUDO_USER}" == "lighttpd" ]; then
|
||||
echo "Security measure: user lighttpd is not allowed to change webUI password!"
|
||||
echo "Exiting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if (( ${#args[2]} > 0 )) ; then
|
||||
readonly PASSWORD="${args[2]}"
|
||||
readonly CONFIRM="${PASSWORD}"
|
||||
else
|
||||
read -s -p "Enter New Password (Blank for no password): " PASSWORD
|
||||
echo ""
|
||||
|
||||
if [ "${PASSWORD}" == "" ]; then
|
||||
change_setting "WEBPASSWORD" ""
|
||||
echo "Password Removed"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
read -s -p "Confirm Password: " CONFIRM
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ "${PASSWORD}" == "${CONFIRM}" ] ; then
|
||||
hash=$(HashPassword ${PASSWORD})
|
||||
# Save hash to file
|
||||
change_setting "WEBPASSWORD" "${hash}"
|
||||
echo "New password set"
|
||||
else
|
||||
echo "Passwords don't match. Your password has not been changed"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
ProcessDNSSettings() {
|
||||
source "${setupVars}"
|
||||
|
||||
delete_dnsmasq_setting "server"
|
||||
|
||||
COUNTER=1
|
||||
while [[ 1 ]]; do
|
||||
var=PIHOLE_DNS_${COUNTER}
|
||||
if [ -z "${!var}" ]; then
|
||||
break;
|
||||
fi
|
||||
add_dnsmasq_setting "server" "${!var}"
|
||||
let COUNTER=COUNTER+1
|
||||
done
|
||||
|
||||
delete_dnsmasq_setting "domain-needed"
|
||||
|
||||
if [[ "${DNS_FQDN_REQUIRED}" == true ]]; then
|
||||
add_dnsmasq_setting "domain-needed"
|
||||
fi
|
||||
|
||||
delete_dnsmasq_setting "bogus-priv"
|
||||
|
||||
if [[ "${DNS_BOGUS_PRIV}" == true ]]; then
|
||||
add_dnsmasq_setting "bogus-priv"
|
||||
fi
|
||||
|
||||
delete_dnsmasq_setting "dnssec"
|
||||
delete_dnsmasq_setting "trust-anchor="
|
||||
|
||||
if [[ "${DNSSEC}" == true ]]; then
|
||||
echo "dnssec
|
||||
trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
|
||||
" >> "${dnsmasqconfig}"
|
||||
fi
|
||||
|
||||
delete_dnsmasq_setting "host-record"
|
||||
|
||||
if [ ! -z "${HOSTRECORD}" ]; then
|
||||
add_dnsmasq_setting "host-record" "${HOSTRECORD}"
|
||||
fi
|
||||
|
||||
# Setup interface listening behavior of dnsmasq
|
||||
delete_dnsmasq_setting "interface"
|
||||
delete_dnsmasq_setting "local-service"
|
||||
|
||||
if [[ "${DNSMASQ_LISTENING}" == "all" ]]; then
|
||||
# Listen on all interfaces, permit all origins
|
||||
add_dnsmasq_setting "except-interface" "nonexisting"
|
||||
elif [[ "${DNSMASQ_LISTENING}" == "local" ]]; then
|
||||
# Listen only on all interfaces, but only local subnets
|
||||
add_dnsmasq_setting "local-service"
|
||||
else
|
||||
# Listen only on one interface
|
||||
add_dnsmasq_setting "interface" "${PIHOLE_INTERFACE}"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
SetDNSServers() {
|
||||
# Save setting to file
|
||||
delete_setting "PIHOLE_DNS"
|
||||
IFS=',' read -r -a array <<< "${args[2]}"
|
||||
for index in "${!array[@]}"
|
||||
do
|
||||
add_setting "PIHOLE_DNS_$((index+1))" "${array[index]}"
|
||||
done
|
||||
|
||||
if [[ "${args[3]}" == "domain-needed" ]]; then
|
||||
change_setting "DNS_FQDN_REQUIRED" "true"
|
||||
else
|
||||
change_setting "DNS_FQDN_REQUIRED" "false"
|
||||
fi
|
||||
|
||||
if [[ "${args[4]}" == "bogus-priv" ]]; then
|
||||
change_setting "DNS_BOGUS_PRIV" "true"
|
||||
else
|
||||
change_setting "DNS_BOGUS_PRIV" "false"
|
||||
fi
|
||||
|
||||
if [[ "${args[5]}" == "dnssec" ]]; then
|
||||
change_setting "DNSSEC" "true"
|
||||
else
|
||||
change_setting "DNSSEC" "false"
|
||||
fi
|
||||
|
||||
ProcessDNSSettings
|
||||
|
||||
# Restart dnsmasq to load new configuration
|
||||
RestartDNS
|
||||
}
|
||||
|
||||
SetExcludeDomains() {
|
||||
change_setting "API_EXCLUDE_DOMAINS" "${args[2]}"
|
||||
}
|
||||
|
||||
SetExcludeClients() {
|
||||
change_setting "API_EXCLUDE_CLIENTS" "${args[2]}"
|
||||
}
|
||||
|
||||
Reboot() {
|
||||
nohup bash -c "sleep 5; reboot" &> /dev/null </dev/null &
|
||||
}
|
||||
|
||||
RestartDNS() {
|
||||
if [ -x "$(command -v systemctl)" ]; then
|
||||
systemctl restart dnsmasq &> /dev/null
|
||||
else
|
||||
service dnsmasq restart &> /dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
SetQueryLogOptions() {
|
||||
change_setting "API_QUERY_LOG_SHOW" "${args[2]}"
|
||||
}
|
||||
|
||||
ProcessDHCPSettings() {
|
||||
source "${setupVars}"
|
||||
|
||||
if [[ "${DHCP_ACTIVE}" == "true" ]]; then
|
||||
interface=$(grep 'PIHOLE_INTERFACE=' /etc/pihole/setupVars.conf | sed "s/.*=//")
|
||||
|
||||
# Use eth0 as fallback interface
|
||||
if [ -z ${interface} ]; then
|
||||
interface="eth0"
|
||||
fi
|
||||
|
||||
if [[ "${PIHOLE_DOMAIN}" == "" ]]; then
|
||||
PIHOLE_DOMAIN="local"
|
||||
change_setting "PIHOLE_DOMAIN" "${PIHOLE_DOMAIN}"
|
||||
fi
|
||||
|
||||
if [[ "${DHCP_LEASETIME}" == "0" ]]; then
|
||||
leasetime="infinite"
|
||||
elif [[ "${DHCP_LEASETIME}" == "" ]]; then
|
||||
leasetime="24h"
|
||||
change_setting "DHCP_LEASETIME" "${leasetime}"
|
||||
else
|
||||
leasetime="${DHCP_LEASETIME}h"
|
||||
fi
|
||||
|
||||
# Write settings to file
|
||||
echo "###############################################################################
|
||||
# DHCP SERVER CONFIG FILE AUTOMATICALLY POPULATED BY PI-HOLE WEB INTERFACE. #
|
||||
# ANY CHANGES MADE TO THIS FILE WILL BE LOST ON CHANGE #
|
||||
###############################################################################
|
||||
dhcp-authoritative
|
||||
dhcp-range=${DHCP_START},${DHCP_END},${leasetime}
|
||||
dhcp-option=option:router,${DHCP_ROUTER}
|
||||
dhcp-leasefile=/etc/pihole/dhcp.leases
|
||||
#quiet-dhcp
|
||||
" > "${dhcpconfig}"
|
||||
|
||||
if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then
|
||||
echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}"
|
||||
fi
|
||||
|
||||
if [[ "${DHCP_IPv6}" == "true" ]]; then
|
||||
echo "#quiet-dhcp6
|
||||
#enable-ra
|
||||
dhcp-option=option6:dns-server,[::]
|
||||
dhcp-range=::100,::1ff,constructor:${interface},ra-names,slaac,${leasetime}
|
||||
ra-param=*,0,0
|
||||
" >> "${dhcpconfig}"
|
||||
fi
|
||||
|
||||
else
|
||||
rm "${dhcpconfig}" &> /dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
EnableDHCP() {
|
||||
change_setting "DHCP_ACTIVE" "true"
|
||||
change_setting "DHCP_START" "${args[2]}"
|
||||
change_setting "DHCP_END" "${args[3]}"
|
||||
change_setting "DHCP_ROUTER" "${args[4]}"
|
||||
change_setting "DHCP_LEASETIME" "${args[5]}"
|
||||
change_setting "PIHOLE_DOMAIN" "${args[6]}"
|
||||
change_setting "DHCP_IPv6" "${args[7]}"
|
||||
|
||||
# Remove possible old setting from file
|
||||
delete_dnsmasq_setting "dhcp-"
|
||||
delete_dnsmasq_setting "quiet-dhcp"
|
||||
|
||||
ProcessDHCPSettings
|
||||
|
||||
RestartDNS
|
||||
}
|
||||
|
||||
DisableDHCP() {
|
||||
change_setting "DHCP_ACTIVE" "false"
|
||||
|
||||
# Remove possible old setting from file
|
||||
delete_dnsmasq_setting "dhcp-"
|
||||
delete_dnsmasq_setting "quiet-dhcp"
|
||||
|
||||
ProcessDHCPSettings
|
||||
|
||||
RestartDNS
|
||||
}
|
||||
|
||||
SetWebUILayout() {
|
||||
change_setting "WEBUIBOXEDLAYOUT" "${args[2]}"
|
||||
}
|
||||
|
||||
CustomizeAdLists() {
|
||||
list="/etc/pihole/adlists.list"
|
||||
|
||||
if [[ "${args[2]}" == "enable" ]]; then
|
||||
sed -i "\\@${args[3]}@s/^#http/http/g" "${list}"
|
||||
elif [[ "${args[2]}" == "disable" ]]; then
|
||||
sed -i "\\@${args[3]}@s/^http/#http/g" "${list}"
|
||||
elif [[ "${args[2]}" == "add" ]]; then
|
||||
echo "${args[3]}" >> ${list}
|
||||
elif [[ "${args[2]}" == "del" ]]; then
|
||||
var=$(echo "${args[3]}" | sed 's/\//\\\//g')
|
||||
sed -i "/${var}/Id" "${list}"
|
||||
else
|
||||
echo "Not permitted"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
SetPrivacyMode() {
|
||||
if [[ "${args[2]}" == "true" ]]; then
|
||||
change_setting "API_PRIVACY_MODE" "true"
|
||||
else
|
||||
change_setting "API_PRIVACY_MODE" "false"
|
||||
fi
|
||||
}
|
||||
|
||||
ResolutionSettings() {
|
||||
typ="${args[2]}"
|
||||
state="${args[3]}"
|
||||
|
||||
if [[ "${typ}" == "forward" ]]; then
|
||||
change_setting "API_GET_UPSTREAM_DNS_HOSTNAME" "${state}"
|
||||
elif [[ "${typ}" == "clients" ]]; then
|
||||
change_setting "API_GET_CLIENT_HOSTNAME" "${state}"
|
||||
fi
|
||||
}
|
||||
|
||||
AddDHCPStaticAddress() {
|
||||
mac="${args[2]}"
|
||||
ip="${args[3]}"
|
||||
host="${args[4]}"
|
||||
|
||||
if [[ "${ip}" == "noip" ]]; then
|
||||
# Static host name
|
||||
echo "dhcp-host=${mac},${host}" >> "${dhcpstaticconfig}"
|
||||
elif [[ "${host}" == "nohost" ]]; then
|
||||
# Static IP
|
||||
echo "dhcp-host=${mac},${ip}" >> "${dhcpstaticconfig}"
|
||||
else
|
||||
# Full info given
|
||||
echo "dhcp-host=${mac},${ip},${host}" >> "${dhcpstaticconfig}"
|
||||
fi
|
||||
}
|
||||
|
||||
RemoveDHCPStaticAddress() {
|
||||
mac="${args[2]}"
|
||||
sed -i "/dhcp-host=${mac}.*/d" "${dhcpstaticconfig}"
|
||||
}
|
||||
|
||||
SetHostRecord() {
|
||||
if [ -n "${args[3]}" ]; then
|
||||
change_setting "HOSTRECORD" "${args[2]},${args[3]}"
|
||||
echo "Setting host record for ${args[2]} -> ${args[3]}"
|
||||
else
|
||||
change_setting "HOSTRECORD" ""
|
||||
echo "Removing host record"
|
||||
fi
|
||||
|
||||
ProcessDNSSettings
|
||||
|
||||
# Restart dnsmasq to load new configuration
|
||||
RestartDNS
|
||||
}
|
||||
|
||||
SetListeningMode() {
|
||||
source "${setupVars}"
|
||||
|
||||
if [[ "$3" == "-h" ]] || [[ "$3" == "--help" ]]; then
|
||||
echo "Usage: pihole -a -i [interface]
|
||||
Example: 'pihole -a -i local'
|
||||
Specify dnsmasq's network interface listening behavior
|
||||
|
||||
Interfaces:
|
||||
local Listen on all interfaces, but only allow queries from
|
||||
devices that are at most one hop away (local devices)
|
||||
single Listen only on ${PIHOLE_INTERFACE} interface
|
||||
all Listen on all interfaces, permit all origins"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "${args[2]}" == "all" ]]; then
|
||||
echo "Listening on all interfaces, permiting all origins, hope you have a firewall!"
|
||||
change_setting "DNSMASQ_LISTENING" "all"
|
||||
elif [[ "${args[2]}" == "local" ]]; then
|
||||
echo "Listening on all interfaces, permitting only origins that are at most one hop away (local devices)"
|
||||
change_setting "DNSMASQ_LISTENING" "local"
|
||||
else
|
||||
echo "Listening only on interface ${PIHOLE_INTERFACE}"
|
||||
change_setting "DNSMASQ_LISTENING" "single"
|
||||
fi
|
||||
|
||||
# Don't restart DNS server yet because other settings
|
||||
# will be applied afterwards if "-web" is set
|
||||
if [[ "${args[3]}" != "-web" ]]; then
|
||||
ProcessDNSSettings
|
||||
# Restart dnsmasq to load new configuration
|
||||
RestartDNS
|
||||
fi
|
||||
}
|
||||
|
||||
Teleporter() {
|
||||
local datetimestamp=$(date "+%Y-%m-%d_%H-%M-%S")
|
||||
php /var/www/html/admin/scripts/pi-hole/php/teleporter.php > "pi-hole-teleporter_${datetimestamp}.zip"
|
||||
}
|
||||
|
||||
main() {
|
||||
args=("$@")
|
||||
|
||||
case "${args[1]}" in
|
||||
"-p" | "password" ) SetWebPassword;;
|
||||
"-c" | "celsius" ) unit="C"; SetTemperatureUnit;;
|
||||
"-f" | "fahrenheit" ) unit="F"; SetTemperatureUnit;;
|
||||
"-k" | "kelvin" ) unit="K"; SetTemperatureUnit;;
|
||||
"setdns" ) SetDNSServers;;
|
||||
"setexcludedomains" ) SetExcludeDomains;;
|
||||
"setexcludeclients" ) SetExcludeClients;;
|
||||
"reboot" ) Reboot;;
|
||||
"restartdns" ) RestartDNS;;
|
||||
"setquerylog" ) SetQueryLogOptions;;
|
||||
"enabledhcp" ) EnableDHCP;;
|
||||
"disabledhcp" ) DisableDHCP;;
|
||||
"layout" ) SetWebUILayout;;
|
||||
"-h" | "--help" ) helpFunc;;
|
||||
"privacymode" ) SetPrivacyMode;;
|
||||
"resolve" ) ResolutionSettings;;
|
||||
"addstaticdhcp" ) AddDHCPStaticAddress;;
|
||||
"removestaticdhcp" ) RemoveDHCPStaticAddress;;
|
||||
"hostrecord" ) SetHostRecord;;
|
||||
"-i" | "interface" ) SetListeningMode "$@";;
|
||||
"-t" | "teleporter" ) Teleporter;;
|
||||
"adlist" ) CustomizeAdLists;;
|
||||
* ) helpFunc;;
|
||||
esac
|
||||
|
||||
shift
|
||||
|
||||
if [[ $# = 0 ]]; then
|
||||
helpFunc
|
||||
fi
|
||||
}
|
@@ -1,44 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ $# = 0 ]; then
|
||||
echo "Immediately whitelists one or more domains."
|
||||
echo "Usage: whitelist.sh domain1 [domain2 ...]"
|
||||
fi
|
||||
|
||||
combopattern=""
|
||||
|
||||
# For each argument passed to this script
|
||||
for var in "$@"
|
||||
do
|
||||
echo "Whitelisting $var..."
|
||||
|
||||
# Construct basic pattern to match domain name.
|
||||
basicpattern=$(echo $var | awk -F '[# \t]' 'NF>0&&$1!="" {print ""$1""}' | sed 's/\./\\./g')
|
||||
|
||||
if [ "$basicpattern" != "" ]; then
|
||||
# Add to the combination pattern that will be used below
|
||||
if [ "$combopattern" != "" ]; then combopattern="$combopattern|"; fi
|
||||
combopattern="$combopattern$basicpattern"
|
||||
|
||||
# Also add the domain to the whitelist but only if it's not already present
|
||||
grep -E -q "^$basicpattern$" /etc/pihole/whitelist.txt \
|
||||
|| echo "$var" >> /etc/pihole/whitelist.txt
|
||||
fi
|
||||
done
|
||||
|
||||
# Now report on and remove matched domains
|
||||
if [ "$combopattern" != "" ]; then
|
||||
echo "Modifying hosts file..."
|
||||
|
||||
# Construct pattern to match entry in hosts file.
|
||||
# This consists of one or more IP addresses followed by the domain name.
|
||||
pattern=$(echo $combopattern | awk -F '[# \t]' '{printf "%s", "^(([0-9]+\.){3}[0-9]+ +)+("$1")$"}')
|
||||
|
||||
# Output what will be removed and then actually remove
|
||||
sed -r -n 's/'"$pattern"'/ Removed: \3/p' /etc/pihole/gravity.list
|
||||
sed -r -i '/'"$pattern"'/d' /etc/pihole/gravity.list
|
||||
|
||||
echo "** $# domain(s) whitelisted."
|
||||
# Force dnsmasq to reload /etc/pihole/gravity.list
|
||||
kill -HUP $(pidof dnsmasq)
|
||||
fi
|
11
advanced/bash-completion/pihole
Normal file
11
advanced/bash-completion/pihole
Normal file
@@ -0,0 +1,11 @@
|
||||
_pihole() {
|
||||
local cur prev opts
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
opts="admin blacklist chronometer debug disable enable flush help logging query reconfigure restartdns setupLCD status tail uninstall updateGravity updatePihole version whitelist checkout"
|
||||
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
}
|
||||
complete -F _pihole pihole
|
136
advanced/blockingpage.css
Normal file
136
advanced/blockingpage.css
Normal file
@@ -0,0 +1,136 @@
|
||||
/* CSS Reset */
|
||||
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; }
|
||||
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; }
|
||||
body { line-height: 1; }
|
||||
ol, ul { list-style: none; }
|
||||
blockquote, q { quotes: none; }
|
||||
blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; }
|
||||
table { border-collapse: collapse; border-spacing: 0; }
|
||||
html { height: 100%; overflow-x: hidden; }
|
||||
|
||||
/* General Style */
|
||||
a { color: rgba(0,60,120,0.95); text-decoration: none; } /* 1E3C5A */
|
||||
a:hover { color: rgba(210,120,0,0.95); transition-duration: .2s; } /* 255, 128, 0 */
|
||||
divs a { border-bottom: 1px dashed rgba(30,60,90,0.3); }
|
||||
b { font-weight: bold; }
|
||||
i { font-style: italic; }
|
||||
|
||||
footer, pre, td { font-family: monospace; padding-left: 15px; }
|
||||
/*body, header { background: #E1E1E1; }*/
|
||||
|
||||
body {
|
||||
background-image: -webkit-linear-gradient(top, rgba(240,240,240,0.95), rgba(190,190,190,0.95));
|
||||
background-image: linear-gradient(to bottom, rgba(240,240,240,0.95), rgba(190,190,190,0.95));
|
||||
background-attachment: fixed;
|
||||
color: rgba(64,64,64,0.95);
|
||||
font: 14px, sans-serif;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
header {
|
||||
min-width: 320px;
|
||||
width: 100%;
|
||||
text-shadow: 0 1px rgba(255,255,255,0.6);
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
border: 1px solid rgba(0,0,0,0.25);
|
||||
border-top-color: rgba(255,255,255,0.85);
|
||||
border-style: solid none;
|
||||
background-image: -webkit-linear-gradient(top, rgba(240,240,240,0.95), rgba(220,220,220,0.95));
|
||||
background-image: linear-gradient(to bottom, rgba(240,240,240,0.95), rgba(220,220,220,0.95));
|
||||
box-shadow: 0 0 1px 1px rgba(0,0,0,0.04);
|
||||
}
|
||||
|
||||
header h1, header div {
|
||||
display: table-cell;
|
||||
color: inherit;
|
||||
font-weight: bold;
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
header h1 {
|
||||
font-size: 22px;
|
||||
font-weight: bold;
|
||||
width: 100%;
|
||||
padding: 8px 0;
|
||||
text-indent: 32px;
|
||||
background: url("http://pi.hole/admin/img/logo.svg") left no-repeat;
|
||||
background-size: 30px 22px;
|
||||
}
|
||||
|
||||
header h1 a, h1 a:hover { color: inherit; }
|
||||
header .alt { width: 85px; font-size: 0.8em; padding-right: 4px; text-align: right; line-height: 1.25em; }
|
||||
.active { color: green; }
|
||||
.inactive { color: red; }
|
||||
|
||||
main {
|
||||
display: block;
|
||||
width: 80%;
|
||||
padding: 10px;
|
||||
font-size: 1em;
|
||||
background-color: rgba(255,255,255,0.85);
|
||||
margin: 8px auto;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid rgba(0,0,0,0.25);
|
||||
box-shadow: 4px 4px rgba(0,0,0,0.1);
|
||||
line-height: 1.2em;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
h2 { /* Rgba is shared with .transparent th */
|
||||
font: 1.15em sans-serif;
|
||||
background-color: rgba(255,0,0,0.4);
|
||||
text-shadow: none;
|
||||
line-height: 1.1em;
|
||||
padding-bottom: 1px;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 4px;
|
||||
background: -webkit-linear-gradient(left, rgba(0,0,0,0.25), transparent 80%) no-repeat;
|
||||
background: linear-gradient(to right, rgba(0,0,0,0.25), transparent 80%) no-repeat;
|
||||
background-size: 100% 1px;
|
||||
background-position: 0 17px;
|
||||
}
|
||||
|
||||
h2:first-child { margin-top: 0; }
|
||||
h2 ~ *:not(h2) { margin-left: 4px; }
|
||||
li { padding: 2px 0; }
|
||||
li::before { content: "\00BB\00a0"; }
|
||||
li a { position: relative; top: 1px; } /* Center bullet-point arrows */
|
||||
|
||||
/* Button Style */
|
||||
.buttons a, button, input, .transparent th a { /* Swapped rgba is shared with input[type='url'] */
|
||||
display: inline-block;
|
||||
color: rgba(32,32,32,0.9);
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
text-shadow: 0 1px rgba(255,255,255,0.2);
|
||||
line-height: 0.86em;
|
||||
font-size: 1em;
|
||||
padding: 4px 8px;
|
||||
background: #FAFAFA;
|
||||
background-image: -webkit-linear-gradient(top, rgba(255,255,255,0.05), rgba(0,0,0,0.05));
|
||||
background-image: linear-gradient(to bottom, rgba(255,255,255,0.05), rgba(0,0,0,0.05));
|
||||
border: 1px solid rgba(0,0,0,0.25);
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 0 rgba(0,0,0,0.04);
|
||||
}
|
||||
|
||||
.buttons { white-space: nowrap; width: 100%; display: table; }
|
||||
.buttons33 { white-space: nowrap; width: 33.333%; display: table; text-align: center; margin-left: 33.333% }
|
||||
.mini a { width: 50%; }
|
||||
a.safe { background-color: rgba(0,220,0,0.5); }
|
||||
button.safe { background-color: rgba(0,220,0,0.5); }
|
||||
a.warn { background-color: rgba(220,0,0,0.5); }
|
||||
|
||||
.blocked a, .mini a { display: table-cell; }
|
||||
.blocked a.safe50 { width: 50%; background-color: rgba(0,220,0,0.5); }
|
||||
.blocked a.safe33 { width: 33.333%; background-color: rgba(0,220,0,0.5); }
|
||||
|
||||
/* Types of text */
|
||||
.msg { white-space: pre; overflow: auto; -webkit-overflow-scrolling: touch; display: block; line-height: 1.2em; font-weight: bold; font-size: 1.15em; margin: 4px 8px 8px 8px; white-space: pre-line; }
|
||||
|
||||
footer { font-size: 0.8em; text-align: center; width: 87%; margin: 4px auto; }
|
1
advanced/cmdline.txt
Normal file
1
advanced/cmdline.txt
Normal file
@@ -0,0 +1 @@
|
||||
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
|
17
advanced/console-setup
Normal file
17
advanced/console-setup
Normal file
@@ -0,0 +1,17 @@
|
||||
# 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,12 +0,0 @@
|
||||
addn-hosts=/etc/pihole/gravity.list
|
||||
domain-needed
|
||||
bogus-priv
|
||||
no-resolv
|
||||
server=8.8.8.8
|
||||
server=8.8.4.4
|
||||
interface=eth0
|
||||
listen-address=127.0.0.1
|
||||
cache-size=10000
|
||||
log-queries
|
||||
log-facility=/var/log/pihole.log
|
||||
local-ttl=300
|
648
advanced/dnsmasq.conf.original
Normal file
648
advanced/dnsmasq.conf.original
Normal file
@@ -0,0 +1,648 @@
|
||||
# Configuration file for dnsmasq.
|
||||
#
|
||||
# Format is one option per line, legal options are the same
|
||||
# as the long options legal on the command line. See
|
||||
# "/usr/sbin/dnsmasq --help" or "man 8 dnsmasq" for details.
|
||||
|
||||
# Listen on this specific port instead of the standard DNS port
|
||||
# (53). Setting this to zero completely disables DNS function,
|
||||
# leaving only DHCP and/or TFTP.
|
||||
#port=5353
|
||||
|
||||
# The following two options make you a better netizen, since they
|
||||
# tell dnsmasq to filter out queries which the public DNS cannot
|
||||
# answer, and which load the servers (especially the root servers)
|
||||
# unnecessarily. If you have a dial-on-demand link they also stop
|
||||
# these requests from bringing up the link unnecessarily.
|
||||
|
||||
# Never forward plain names (without a dot or domain part)
|
||||
#domain-needed
|
||||
# Never forward addresses in the non-routed address spaces.
|
||||
#bogus-priv
|
||||
|
||||
# Uncomment these to enable DNSSEC validation and caching:
|
||||
# (Requires dnsmasq to be built with DNSSEC option.)
|
||||
#conf-file=%%PREFIX%%/share/dnsmasq/trust-anchors.conf
|
||||
#dnssec
|
||||
|
||||
# Replies which are not DNSSEC signed may be legitimate, because the domain
|
||||
# is unsigned, or may be forgeries. Setting this option tells dnsmasq to
|
||||
# check that an unsigned reply is OK, by finding a secure proof that a DS
|
||||
# record somewhere between the root and the domain does not exist.
|
||||
# The cost of setting this is that even queries in unsigned domains will need
|
||||
# one or more extra DNS queries to verify.
|
||||
#dnssec-check-unsigned
|
||||
|
||||
# Uncomment this to filter useless windows-originated DNS requests
|
||||
# which can trigger dial-on-demand links needlessly.
|
||||
# Note that (amongst other things) this blocks all SRV requests,
|
||||
# so don't use it if you use eg Kerberos, SIP, XMMP or Google-talk.
|
||||
# This option only affects forwarding, SRV records originating for
|
||||
# dnsmasq (via srv-host= lines) are not suppressed by it.
|
||||
#filterwin2k
|
||||
|
||||
# Change this line if you want dns to get its upstream servers from
|
||||
# somewhere other that /etc/resolv.conf
|
||||
#resolv-file=
|
||||
|
||||
# By default, dnsmasq will send queries to any of the upstream
|
||||
# servers it knows about and tries to favour servers to are known
|
||||
# to be up. Uncommenting this forces dnsmasq to try each query
|
||||
# with each server strictly in the order they appear in
|
||||
# /etc/resolv.conf
|
||||
#strict-order
|
||||
|
||||
# If you don't want dnsmasq to read /etc/resolv.conf or any other
|
||||
# file, getting its servers from this file instead (see below), then
|
||||
# uncomment this.
|
||||
#no-resolv
|
||||
|
||||
# If you don't want dnsmasq to poll /etc/resolv.conf or other resolv
|
||||
# files for changes and re-read them then uncomment this.
|
||||
#no-poll
|
||||
|
||||
# Add other name servers here, with domain specs if they are for
|
||||
# non-public domains.
|
||||
#server=/localnet/192.168.0.1
|
||||
|
||||
# Example of routing PTR queries to nameservers: this will send all
|
||||
# address->name queries for 192.168.3/24 to nameserver 10.1.2.3
|
||||
#server=/3.168.192.in-addr.arpa/10.1.2.3
|
||||
|
||||
# Add local-only domains here, queries in these domains are answered
|
||||
# from /etc/hosts or DHCP only.
|
||||
#local=/localnet/
|
||||
|
||||
# Add domains which you want to force to an IP address here.
|
||||
# The example below send any host in double-click.net to a local
|
||||
# web-server.
|
||||
#address=/double-click.net/127.0.0.1
|
||||
|
||||
# --address (and --server) work with IPv6 addresses too.
|
||||
#address=/www.thekelleys.org.uk/fe80::20d:60ff:fe36:f83
|
||||
|
||||
# Add the IPs of all queries to yahoo.com, google.com, and their
|
||||
# subdomains to the vpn and search ipsets:
|
||||
#ipset=/yahoo.com/google.com/vpn,search
|
||||
|
||||
# You can control how dnsmasq talks to a server: this forces
|
||||
# queries to 10.1.2.3 to be routed via eth1
|
||||
# server=10.1.2.3@eth1
|
||||
|
||||
# and this sets the source (ie local) address used to talk to
|
||||
# 10.1.2.3 to 192.168.1.1 port 55 (there must be a interface with that
|
||||
# IP on the machine, obviously).
|
||||
# server=10.1.2.3@192.168.1.1#55
|
||||
|
||||
# If you want dnsmasq to change uid and gid to something other
|
||||
# than the default, edit the following lines.
|
||||
#user=
|
||||
#group=
|
||||
|
||||
# If you want dnsmasq to listen for DHCP and DNS requests only on
|
||||
# specified interfaces (and the loopback) give the name of the
|
||||
# interface (eg eth0) here.
|
||||
# Repeat the line for more than one interface.
|
||||
#interface=
|
||||
# Or you can specify which interface _not_ to listen on
|
||||
#except-interface=
|
||||
# Or which to listen on by address (remember to include 127.0.0.1 if
|
||||
# you use this.)
|
||||
#listen-address=
|
||||
# If you want dnsmasq to provide only DNS service on an interface,
|
||||
# configure it as shown above, and then use the following line to
|
||||
# disable DHCP and TFTP on it.
|
||||
#no-dhcp-interface=
|
||||
|
||||
# On systems which support it, dnsmasq binds the wildcard address,
|
||||
# even when it is listening on only some interfaces. It then discards
|
||||
# requests that it shouldn't reply to. This has the advantage of
|
||||
# working even when interfaces come and go and change address. If you
|
||||
# want dnsmasq to really bind only the interfaces it is listening on,
|
||||
# uncomment this option. About the only time you may need this is when
|
||||
# running another nameserver on the same machine.
|
||||
#bind-interfaces
|
||||
|
||||
# If you don't want dnsmasq to read /etc/hosts, uncomment the
|
||||
# following line.
|
||||
#no-hosts
|
||||
# or if you want it to read another file, as well as /etc/hosts, use
|
||||
# this.
|
||||
#addn-hosts=/etc/banner_add_hosts
|
||||
|
||||
# Set this (and domain: see below) if you want to have a domain
|
||||
# automatically added to simple names in a hosts-file.
|
||||
#expand-hosts
|
||||
|
||||
# Set the domain for dnsmasq. this is optional, but if it is set, it
|
||||
# does the following things.
|
||||
# 1) Allows DHCP hosts to have fully qualified domain names, as long
|
||||
# as the domain part matches this setting.
|
||||
# 2) Sets the "domain" DHCP option thereby potentially setting the
|
||||
# domain of all systems configured by DHCP
|
||||
# 3) Provides the domain part for "expand-hosts"
|
||||
#domain=thekelleys.org.uk
|
||||
|
||||
# Set a different domain for a particular subnet
|
||||
#domain=wireless.thekelleys.org.uk,192.168.2.0/24
|
||||
|
||||
# Same idea, but range rather then subnet
|
||||
#domain=reserved.thekelleys.org.uk,192.68.3.100,192.168.3.200
|
||||
|
||||
# Uncomment this to enable the integrated DHCP server, you need
|
||||
# to supply the range of addresses available for lease and optionally
|
||||
# a lease time. If you have more than one network, you will need to
|
||||
# repeat this for each network on which you want to supply DHCP
|
||||
# service.
|
||||
#dhcp-range=192.168.0.50,192.168.0.150,12h
|
||||
|
||||
# This is an example of a DHCP range where the netmask is given. This
|
||||
# is needed for networks we reach the dnsmasq DHCP server via a relay
|
||||
# agent. If you don't know what a DHCP relay agent is, you probably
|
||||
# don't need to worry about this.
|
||||
#dhcp-range=192.168.0.50,192.168.0.150,255.255.255.0,12h
|
||||
|
||||
# This is an example of a DHCP range which sets a tag, so that
|
||||
# some DHCP options may be set only for this network.
|
||||
#dhcp-range=set:red,192.168.0.50,192.168.0.150
|
||||
|
||||
# Use this DHCP range only when the tag "green" is set.
|
||||
#dhcp-range=tag:green,192.168.0.50,192.168.0.150,12h
|
||||
|
||||
# Specify a subnet which can't be used for dynamic address allocation,
|
||||
# is available for hosts with matching --dhcp-host lines. Note that
|
||||
# dhcp-host declarations will be ignored unless there is a dhcp-range
|
||||
# of some type for the subnet in question.
|
||||
# In this case the netmask is implied (it comes from the network
|
||||
# configuration on the machine running dnsmasq) it is possible to give
|
||||
# an explicit netmask instead.
|
||||
#dhcp-range=192.168.0.0,static
|
||||
|
||||
# Enable DHCPv6. Note that the prefix-length does not need to be specified
|
||||
# and defaults to 64 if missing/
|
||||
#dhcp-range=1234::2, 1234::500, 64, 12h
|
||||
|
||||
# Do Router Advertisements, BUT NOT DHCP for this subnet.
|
||||
#dhcp-range=1234::, ra-only
|
||||
|
||||
# Do Router Advertisements, BUT NOT DHCP for this subnet, also try and
|
||||
# add names to the DNS for the IPv6 address of SLAAC-configured dual-stack
|
||||
# hosts. Use the DHCPv4 lease to derive the name, network segment and
|
||||
# MAC address and assume that the host will also have an
|
||||
# IPv6 address calculated using the SLAAC alogrithm.
|
||||
#dhcp-range=1234::, ra-names
|
||||
|
||||
# Do Router Advertisements, BUT NOT DHCP for this subnet.
|
||||
# Set the lifetime to 46 hours. (Note: minimum lifetime is 2 hours.)
|
||||
#dhcp-range=1234::, ra-only, 48h
|
||||
|
||||
# Do DHCP and Router Advertisements for this subnet. Set the A bit in the RA
|
||||
# so that clients can use SLAAC addresses as well as DHCP ones.
|
||||
#dhcp-range=1234::2, 1234::500, slaac
|
||||
|
||||
# Do Router Advertisements and stateless DHCP for this subnet. Clients will
|
||||
# not get addresses from DHCP, but they will get other configuration information.
|
||||
# They will use SLAAC for addresses.
|
||||
#dhcp-range=1234::, ra-stateless
|
||||
|
||||
# Do stateless DHCP, SLAAC, and generate DNS names for SLAAC addresses
|
||||
# from DHCPv4 leases.
|
||||
#dhcp-range=1234::, ra-stateless, ra-names
|
||||
|
||||
# Do router advertisements for all subnets where we're doing DHCPv6
|
||||
# Unless overriden by ra-stateless, ra-names, et al, the router
|
||||
# advertisements will have the M and O bits set, so that the clients
|
||||
# get addresses and configuration from DHCPv6, and the A bit reset, so the
|
||||
# clients don't use SLAAC addresses.
|
||||
#enable-ra
|
||||
|
||||
# Supply parameters for specified hosts using DHCP. There are lots
|
||||
# of valid alternatives, so we will give examples of each. Note that
|
||||
# IP addresses DO NOT have to be in the range given above, they just
|
||||
# need to be on the same network. The order of the parameters in these
|
||||
# do not matter, it's permissible to give name, address and MAC in any
|
||||
# order.
|
||||
|
||||
# Always allocate the host with Ethernet address 11:22:33:44:55:66
|
||||
# The IP address 192.168.0.60
|
||||
#dhcp-host=11:22:33:44:55:66,192.168.0.60
|
||||
|
||||
# Always set the name of the host with hardware address
|
||||
# 11:22:33:44:55:66 to be "fred"
|
||||
#dhcp-host=11:22:33:44:55:66,fred
|
||||
|
||||
# Always give the host with Ethernet address 11:22:33:44:55:66
|
||||
# the name fred and IP address 192.168.0.60 and lease time 45 minutes
|
||||
#dhcp-host=11:22:33:44:55:66,fred,192.168.0.60,45m
|
||||
|
||||
# Give a host with Ethernet address 11:22:33:44:55:66 or
|
||||
# 12:34:56:78:90:12 the IP address 192.168.0.60. Dnsmasq will assume
|
||||
# that these two Ethernet interfaces will never be in use at the same
|
||||
# time, and give the IP address to the second, even if it is already
|
||||
# in use by the first. Useful for laptops with wired and wireless
|
||||
# addresses.
|
||||
#dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.60
|
||||
|
||||
# Give the machine which says its name is "bert" IP address
|
||||
# 192.168.0.70 and an infinite lease
|
||||
#dhcp-host=bert,192.168.0.70,infinite
|
||||
|
||||
# Always give the host with client identifier 01:02:02:04
|
||||
# the IP address 192.168.0.60
|
||||
#dhcp-host=id:01:02:02:04,192.168.0.60
|
||||
|
||||
# Always give the host with client identifier "marjorie"
|
||||
# the IP address 192.168.0.60
|
||||
#dhcp-host=id:marjorie,192.168.0.60
|
||||
|
||||
# Enable the address given for "judge" in /etc/hosts
|
||||
# to be given to a machine presenting the name "judge" when
|
||||
# it asks for a DHCP lease.
|
||||
#dhcp-host=judge
|
||||
|
||||
# Never offer DHCP service to a machine whose Ethernet
|
||||
# address is 11:22:33:44:55:66
|
||||
#dhcp-host=11:22:33:44:55:66,ignore
|
||||
|
||||
# Ignore any client-id presented by the machine with Ethernet
|
||||
# address 11:22:33:44:55:66. This is useful to prevent a machine
|
||||
# being treated differently when running under different OS's or
|
||||
# between PXE boot and OS boot.
|
||||
#dhcp-host=11:22:33:44:55:66,id:*
|
||||
|
||||
# Send extra options which are tagged as "red" to
|
||||
# the machine with Ethernet address 11:22:33:44:55:66
|
||||
#dhcp-host=11:22:33:44:55:66,set:red
|
||||
|
||||
# Send extra options which are tagged as "red" to
|
||||
# any machine with Ethernet address starting 11:22:33:
|
||||
#dhcp-host=11:22:33:*:*:*,set:red
|
||||
|
||||
# Give a fixed IPv6 address and name to client with
|
||||
# DUID 00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2
|
||||
# Note the MAC addresses CANNOT be used to identify DHCPv6 clients.
|
||||
# Note also the they [] around the IPv6 address are obilgatory.
|
||||
#dhcp-host=id:00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2, fred, [1234::5]
|
||||
|
||||
# Ignore any clients which are not specified in dhcp-host lines
|
||||
# or /etc/ethers. Equivalent to ISC "deny unknown-clients".
|
||||
# This relies on the special "known" tag which is set when
|
||||
# a host is matched.
|
||||
#dhcp-ignore=tag:!known
|
||||
|
||||
# Send extra options which are tagged as "red" to any machine whose
|
||||
# DHCP vendorclass string includes the substring "Linux"
|
||||
#dhcp-vendorclass=set:red,Linux
|
||||
|
||||
# Send extra options which are tagged as "red" to any machine one
|
||||
# of whose DHCP userclass strings includes the substring "accounts"
|
||||
#dhcp-userclass=set:red,accounts
|
||||
|
||||
# Send extra options which are tagged as "red" to any machine whose
|
||||
# MAC address matches the pattern.
|
||||
#dhcp-mac=set:red,00:60:8C:*:*:*
|
||||
|
||||
# If this line is uncommented, dnsmasq will read /etc/ethers and act
|
||||
# on the ethernet-address/IP pairs found there just as if they had
|
||||
# been given as --dhcp-host options. Useful if you keep
|
||||
# MAC-address/host mappings there for other purposes.
|
||||
#read-ethers
|
||||
|
||||
# Send options to hosts which ask for a DHCP lease.
|
||||
# See RFC 2132 for details of available options.
|
||||
# Common options can be given to dnsmasq by name:
|
||||
# run "dnsmasq --help dhcp" to get a list.
|
||||
# Note that all the common settings, such as netmask and
|
||||
# broadcast address, DNS server and default route, are given
|
||||
# sane defaults by dnsmasq. You very likely will not need
|
||||
# any dhcp-options. If you use Windows clients and Samba, there
|
||||
# are some options which are recommended, they are detailed at the
|
||||
# end of this section.
|
||||
|
||||
# Override the default route supplied by dnsmasq, which assumes the
|
||||
# router is the same machine as the one running dnsmasq.
|
||||
#dhcp-option=3,1.2.3.4
|
||||
|
||||
# Do the same thing, but using the option name
|
||||
#dhcp-option=option:router,1.2.3.4
|
||||
|
||||
# Override the default route supplied by dnsmasq and send no default
|
||||
# route at all. Note that this only works for the options sent by
|
||||
# default (1, 3, 6, 12, 28) the same line will send a zero-length option
|
||||
# for all other option numbers.
|
||||
#dhcp-option=3
|
||||
|
||||
# Set the NTP time server addresses to 192.168.0.4 and 10.10.0.5
|
||||
#dhcp-option=option:ntp-server,192.168.0.4,10.10.0.5
|
||||
|
||||
# Send DHCPv6 option. Note [] around IPv6 addresses.
|
||||
#dhcp-option=option6:dns-server,[1234::77],[1234::88]
|
||||
|
||||
# Send DHCPv6 option for namservers as the machine running
|
||||
# dnsmasq and another.
|
||||
#dhcp-option=option6:dns-server,[::],[1234::88]
|
||||
|
||||
# Ask client to poll for option changes every six hours. (RFC4242)
|
||||
#dhcp-option=option6:information-refresh-time,6h
|
||||
|
||||
# Set the NTP time server address to be the same machine as
|
||||
# is running dnsmasq
|
||||
#dhcp-option=42,0.0.0.0
|
||||
|
||||
# Set the NIS domain name to "welly"
|
||||
#dhcp-option=40,welly
|
||||
|
||||
# Set the default time-to-live to 50
|
||||
#dhcp-option=23,50
|
||||
|
||||
# Set the "all subnets are local" flag
|
||||
#dhcp-option=27,1
|
||||
|
||||
# Send the etherboot magic flag and then etherboot options (a string).
|
||||
#dhcp-option=128,e4:45:74:68:00:00
|
||||
#dhcp-option=129,NIC=eepro100
|
||||
|
||||
# Specify an option which will only be sent to the "red" network
|
||||
# (see dhcp-range for the declaration of the "red" network)
|
||||
# Note that the tag: part must precede the option: part.
|
||||
#dhcp-option = tag:red, option:ntp-server, 192.168.1.1
|
||||
|
||||
# The following DHCP options set up dnsmasq in the same way as is specified
|
||||
# for the ISC dhcpcd in
|
||||
# http://www.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt
|
||||
# adapted for a typical dnsmasq installation where the host running
|
||||
# dnsmasq is also the host running samba.
|
||||
# you may want to uncomment some or all of them if you use
|
||||
# Windows clients and Samba.
|
||||
#dhcp-option=19,0 # option ip-forwarding off
|
||||
#dhcp-option=44,0.0.0.0 # set netbios-over-TCP/IP nameserver(s) aka WINS server(s)
|
||||
#dhcp-option=45,0.0.0.0 # netbios datagram distribution server
|
||||
#dhcp-option=46,8 # netbios node type
|
||||
|
||||
# Send an empty WPAD option. This may be REQUIRED to get windows 7 to behave.
|
||||
#dhcp-option=252,"\n"
|
||||
|
||||
# Send RFC-3397 DNS domain search DHCP option. WARNING: Your DHCP client
|
||||
# probably doesn't support this......
|
||||
#dhcp-option=option:domain-search,eng.apple.com,marketing.apple.com
|
||||
|
||||
# Send RFC-3442 classless static routes (note the netmask encoding)
|
||||
#dhcp-option=121,192.168.1.0/24,1.2.3.4,10.0.0.0/8,5.6.7.8
|
||||
|
||||
# Send vendor-class specific options encapsulated in DHCP option 43.
|
||||
# The meaning of the options is defined by the vendor-class so
|
||||
# options are sent only when the client supplied vendor class
|
||||
# matches the class given here. (A substring match is OK, so "MSFT"
|
||||
# matches "MSFT" and "MSFT 5.0"). This example sets the
|
||||
# mtftp address to 0.0.0.0 for PXEClients.
|
||||
#dhcp-option=vendor:PXEClient,1,0.0.0.0
|
||||
|
||||
# Send microsoft-specific option to tell windows to release the DHCP lease
|
||||
# when it shuts down. Note the "i" flag, to tell dnsmasq to send the
|
||||
# value as a four-byte integer - that's what microsoft wants. See
|
||||
# http://technet2.microsoft.com/WindowsServer/en/library/a70f1bb7-d2d4-49f0-96d6-4b7414ecfaae1033.mspx?mfr=true
|
||||
#dhcp-option=vendor:MSFT,2,1i
|
||||
|
||||
# Send the Encapsulated-vendor-class ID needed by some configurations of
|
||||
# Etherboot to allow is to recognise the DHCP server.
|
||||
#dhcp-option=vendor:Etherboot,60,"Etherboot"
|
||||
|
||||
# Send options to PXELinux. Note that we need to send the options even
|
||||
# though they don't appear in the parameter request list, so we need
|
||||
# to use dhcp-option-force here.
|
||||
# See http://syslinux.zytor.com/pxe.php#special for details.
|
||||
# Magic number - needed before anything else is recognised
|
||||
#dhcp-option-force=208,f1:00:74:7e
|
||||
# Configuration file name
|
||||
#dhcp-option-force=209,configs/common
|
||||
# Path prefix
|
||||
#dhcp-option-force=210,/tftpboot/pxelinux/files/
|
||||
# Reboot time. (Note 'i' to send 32-bit value)
|
||||
#dhcp-option-force=211,30i
|
||||
|
||||
# Set the boot filename for netboot/PXE. You will only need
|
||||
# this is you want to boot machines over the network and you will need
|
||||
# a TFTP server; either dnsmasq's built in TFTP server or an
|
||||
# external one. (See below for how to enable the TFTP server.)
|
||||
#dhcp-boot=pxelinux.0
|
||||
|
||||
# The same as above, but use custom tftp-server instead machine running dnsmasq
|
||||
#dhcp-boot=pxelinux,server.name,192.168.1.100
|
||||
|
||||
# Boot for Etherboot gPXE. The idea is to send two different
|
||||
# filenames, the first loads gPXE, and the second tells gPXE what to
|
||||
# load. The dhcp-match sets the gpxe tag for requests from gPXE.
|
||||
#dhcp-match=set:gpxe,175 # gPXE sends a 175 option.
|
||||
#dhcp-boot=tag:!gpxe,undionly.kpxe
|
||||
#dhcp-boot=mybootimage
|
||||
|
||||
# Encapsulated options for Etherboot gPXE. All the options are
|
||||
# encapsulated within option 175
|
||||
#dhcp-option=encap:175, 1, 5b # priority code
|
||||
#dhcp-option=encap:175, 176, 1b # no-proxydhcp
|
||||
#dhcp-option=encap:175, 177, string # bus-id
|
||||
#dhcp-option=encap:175, 189, 1b # BIOS drive code
|
||||
#dhcp-option=encap:175, 190, user # iSCSI username
|
||||
#dhcp-option=encap:175, 191, pass # iSCSI password
|
||||
|
||||
# Test for the architecture of a netboot client. PXE clients are
|
||||
# supposed to send their architecture as option 93. (See RFC 4578)
|
||||
#dhcp-match=peecees, option:client-arch, 0 #x86-32
|
||||
#dhcp-match=itanics, option:client-arch, 2 #IA64
|
||||
#dhcp-match=hammers, option:client-arch, 6 #x86-64
|
||||
#dhcp-match=mactels, option:client-arch, 7 #EFI x86-64
|
||||
|
||||
# Do real PXE, rather than just booting a single file, this is an
|
||||
# alternative to dhcp-boot.
|
||||
#pxe-prompt="What system shall I netboot?"
|
||||
# or with timeout before first available action is taken:
|
||||
#pxe-prompt="Press F8 for menu.", 60
|
||||
|
||||
# Available boot services. for PXE.
|
||||
#pxe-service=x86PC, "Boot from local disk"
|
||||
|
||||
# Loads <tftp-root>/pxelinux.0 from dnsmasq TFTP server.
|
||||
#pxe-service=x86PC, "Install Linux", pxelinux
|
||||
|
||||
# Loads <tftp-root>/pxelinux.0 from TFTP server at 1.2.3.4.
|
||||
# Beware this fails on old PXE ROMS.
|
||||
#pxe-service=x86PC, "Install Linux", pxelinux, 1.2.3.4
|
||||
|
||||
# Use bootserver on network, found my multicast or broadcast.
|
||||
#pxe-service=x86PC, "Install windows from RIS server", 1
|
||||
|
||||
# Use bootserver at a known IP address.
|
||||
#pxe-service=x86PC, "Install windows from RIS server", 1, 1.2.3.4
|
||||
|
||||
# If you have multicast-FTP available,
|
||||
# information for that can be passed in a similar way using options 1
|
||||
# to 5. See page 19 of
|
||||
# http://download.intel.com/design/archives/wfm/downloads/pxespec.pdf
|
||||
|
||||
|
||||
# Enable dnsmasq's built-in TFTP server
|
||||
#enable-tftp
|
||||
|
||||
# Set the root directory for files available via FTP.
|
||||
#tftp-root=/var/ftpd
|
||||
|
||||
# Make the TFTP server more secure: with this set, only files owned by
|
||||
# the user dnsmasq is running as will be send over the net.
|
||||
#tftp-secure
|
||||
|
||||
# This option stops dnsmasq from negotiating a larger blocksize for TFTP
|
||||
# transfers. It will slow things down, but may rescue some broken TFTP
|
||||
# clients.
|
||||
#tftp-no-blocksize
|
||||
|
||||
# Set the boot file name only when the "red" tag is set.
|
||||
#dhcp-boot=tag:red,pxelinux.red-net
|
||||
|
||||
# An example of dhcp-boot with an external TFTP server: the name and IP
|
||||
# address of the server are given after the filename.
|
||||
# Can fail with old PXE ROMS. Overridden by --pxe-service.
|
||||
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3
|
||||
|
||||
# If there are multiple external tftp servers having a same name
|
||||
# (using /etc/hosts) then that name can be specified as the
|
||||
# tftp_servername (the third option to dhcp-boot) and in that
|
||||
# case dnsmasq resolves this name and returns the resultant IP
|
||||
# addresses in round robin fasion. This facility can be used to
|
||||
# load balance the tftp load among a set of servers.
|
||||
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,tftp_server_name
|
||||
|
||||
# Set the limit on DHCP leases, the default is 150
|
||||
#dhcp-lease-max=150
|
||||
|
||||
# The DHCP server needs somewhere on disk to keep its lease database.
|
||||
# This defaults to a sane location, but if you want to change it, use
|
||||
# the line below.
|
||||
#dhcp-leasefile=/var/lib/misc/dnsmasq.leases
|
||||
|
||||
# Set the DHCP server to authoritative mode. In this mode it will barge in
|
||||
# and take over the lease for any client which broadcasts on the network,
|
||||
# whether it has a record of the lease or not. This avoids long timeouts
|
||||
# when a machine wakes up on a new network. DO NOT enable this if there's
|
||||
# the slightest chance that you might end up accidentally configuring a DHCP
|
||||
# server for your campus/company accidentally. The ISC server uses
|
||||
# the same option, and this URL provides more information:
|
||||
# http://www.isc.org/files/auth.html
|
||||
#dhcp-authoritative
|
||||
|
||||
# Run an executable when a DHCP lease is created or destroyed.
|
||||
# The arguments sent to the script are "add" or "del",
|
||||
# then the MAC address, the IP address and finally the hostname
|
||||
# if there is one.
|
||||
#dhcp-script=/bin/echo
|
||||
|
||||
# Set the cachesize here.
|
||||
#cache-size=150
|
||||
|
||||
# If you want to disable negative caching, uncomment this.
|
||||
#no-negcache
|
||||
|
||||
# Normally responses which come from /etc/hosts and the DHCP lease
|
||||
# file have Time-To-Live set as zero, which conventionally means
|
||||
# do not cache further. If you are happy to trade lower load on the
|
||||
# server for potentially stale date, you can set a time-to-live (in
|
||||
# seconds) here.
|
||||
#local-ttl=
|
||||
|
||||
# If you want dnsmasq to detect attempts by Verisign to send queries
|
||||
# to unregistered .com and .net hosts to its sitefinder service and
|
||||
# have dnsmasq instead return the correct NXDOMAIN response, uncomment
|
||||
# this line. You can add similar lines to do the same for other
|
||||
# registries which have implemented wildcard A records.
|
||||
#bogus-nxdomain=64.94.110.11
|
||||
|
||||
# If you want to fix up DNS results from upstream servers, use the
|
||||
# alias option. This only works for IPv4.
|
||||
# This alias makes a result of 1.2.3.4 appear as 5.6.7.8
|
||||
#alias=1.2.3.4,5.6.7.8
|
||||
# and this maps 1.2.3.x to 5.6.7.x
|
||||
#alias=1.2.3.0,5.6.7.0,255.255.255.0
|
||||
# and this maps 192.168.0.10->192.168.0.40 to 10.0.0.10->10.0.0.40
|
||||
#alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0
|
||||
|
||||
# Change these lines if you want dnsmasq to serve MX records.
|
||||
|
||||
# Return an MX record named "maildomain.com" with target
|
||||
# servermachine.com and preference 50
|
||||
#mx-host=maildomain.com,servermachine.com,50
|
||||
|
||||
# Set the default target for MX records created using the localmx option.
|
||||
#mx-target=servermachine.com
|
||||
|
||||
# Return an MX record pointing to the mx-target for all local
|
||||
# machines.
|
||||
#localmx
|
||||
|
||||
# Return an MX record pointing to itself for all local machines.
|
||||
#selfmx
|
||||
|
||||
# Change the following lines if you want dnsmasq to serve SRV
|
||||
# records. These are useful if you want to serve ldap requests for
|
||||
# Active Directory and other windows-originated DNS requests.
|
||||
# See RFC 2782.
|
||||
# You may add multiple srv-host lines.
|
||||
# The fields are <name>,<target>,<port>,<priority>,<weight>
|
||||
# If the domain part if missing from the name (so that is just has the
|
||||
# service and protocol sections) then the domain given by the domain=
|
||||
# config option is used. (Note that expand-hosts does not need to be
|
||||
# set for this to work.)
|
||||
|
||||
# A SRV record sending LDAP for the example.com domain to
|
||||
# ldapserver.example.com port 389
|
||||
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389
|
||||
|
||||
# A SRV record sending LDAP for the example.com domain to
|
||||
# ldapserver.example.com port 389 (using domain=)
|
||||
#domain=example.com
|
||||
#srv-host=_ldap._tcp,ldapserver.example.com,389
|
||||
|
||||
# Two SRV records for LDAP, each with different priorities
|
||||
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,1
|
||||
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,2
|
||||
|
||||
# A SRV record indicating that there is no LDAP server for the domain
|
||||
# example.com
|
||||
#srv-host=_ldap._tcp.example.com
|
||||
|
||||
# The following line shows how to make dnsmasq serve an arbitrary PTR
|
||||
# record. This is useful for DNS-SD. (Note that the
|
||||
# domain-name expansion done for SRV records _does_not
|
||||
# occur for PTR records.)
|
||||
#ptr-record=_http._tcp.dns-sd-services,"New Employee Page._http._tcp.dns-sd-services"
|
||||
|
||||
# Change the following lines to enable dnsmasq to serve TXT records.
|
||||
# These are used for things like SPF and zeroconf. (Note that the
|
||||
# domain-name expansion done for SRV records _does_not
|
||||
# occur for TXT records.)
|
||||
|
||||
#Example SPF.
|
||||
#txt-record=example.com,"v=spf1 a -all"
|
||||
|
||||
#Example zeroconf
|
||||
#txt-record=_http._tcp.example.com,name=value,paper=A4
|
||||
|
||||
# Provide an alias for a "local" DNS name. Note that this _only_ works
|
||||
# for targets which are names from DHCP or /etc/hosts. Give host
|
||||
# "bert" another name, bertrand
|
||||
#cname=bertand,bert
|
||||
|
||||
# For debugging purposes, log each DNS query as it passes through
|
||||
# dnsmasq.
|
||||
#log-queries
|
||||
|
||||
# Log lots of extra information about DHCP transactions.
|
||||
#log-dhcp
|
||||
|
||||
# Include another lot of configuration options.
|
||||
#conf-file=/etc/dnsmasq.more.conf
|
||||
#conf-dir=/etc/dnsmasq.d
|
||||
|
||||
# Include all the files in a directory except those ending in .bak
|
||||
#conf-dir=/etc/dnsmasq.d,.bak
|
||||
|
||||
# Include all files in a directory which end in .conf
|
||||
#conf-dir=/etc/dnsmasq.d/*.conf
|
@@ -1 +0,0 @@
|
||||
CONF_SWAPSIZE=500
|
@@ -1,4 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
1
advanced/index.js
Normal file
1
advanced/index.js
Normal file
@@ -0,0 +1 @@
|
||||
var x = "Pi-hole: A black hole for Internet advertisements."
|
224
advanced/index.php
Normal file
224
advanced/index.php
Normal file
@@ -0,0 +1,224 @@
|
||||
<?php
|
||||
/* Detailed Pi-hole Block Page: Show "Website Blocked" if user browses to site, but not to image/file requests based on the work of WaLLy3K for DietPi & Pi-Hole */
|
||||
|
||||
function validIP($address){
|
||||
if (preg_match('/[.:0]/', $address) && !preg_match('/[1-9a-f]/', $address)) {
|
||||
// Test if address contains either `:` or `0` but not 1-9 or a-f
|
||||
return false;
|
||||
}
|
||||
return !filter_var($address, FILTER_VALIDATE_IP) === false;
|
||||
}
|
||||
|
||||
$uri = escapeshellcmd($_SERVER['REQUEST_URI']);
|
||||
$serverName = escapeshellcmd($_SERVER['SERVER_NAME']);
|
||||
|
||||
// If the server name is 'pi.hole', it's likely a user trying to get to the admin panel.
|
||||
// Let's be nice and redirect them.
|
||||
if ($serverName === 'pi.hole')
|
||||
{
|
||||
header('HTTP/1.1 301 Moved Permanently');
|
||||
header("Location: /admin/");
|
||||
}
|
||||
|
||||
// Retrieve server URI extension (EG: jpg, exe, php)
|
||||
ini_set('pcre.recursion_limit',100);
|
||||
$uriExt = pathinfo($uri, PATHINFO_EXTENSION);
|
||||
|
||||
// Define which URL extensions get rendered as "Website Blocked"
|
||||
$webExt = array('asp', 'htm', 'html', 'php', 'rss', 'xml');
|
||||
|
||||
// Get IPv4 and IPv6 addresses from setupVars.conf (if available)
|
||||
$setupVars = parse_ini_file("/etc/pihole/setupVars.conf");
|
||||
$ipv4 = isset($setupVars["IPV4_ADDRESS"]) ? explode("/", $setupVars["IPV4_ADDRESS"])[0] : $_SERVER['SERVER_ADDR'];
|
||||
$ipv6 = isset($setupVars["IPV6_ADDRESS"]) ? explode("/", $setupVars["IPV6_ADDRESS"])[0] : $_SERVER['SERVER_ADDR'];
|
||||
|
||||
$AUTHORIZED_HOSTNAMES = array(
|
||||
$ipv4,
|
||||
$ipv6,
|
||||
str_replace(array("[","]"), array("",""), $_SERVER["SERVER_ADDR"]),
|
||||
"pi.hole",
|
||||
"localhost");
|
||||
// Allow user set virtual hostnames
|
||||
$virtual_host = getenv('VIRTUAL_HOST');
|
||||
if (!empty($virtual_host))
|
||||
array_push($AUTHORIZED_HOSTNAMES, $virtual_host);
|
||||
|
||||
// Immediately quit since we didn't block this page (the IP address or pi.hole is explicitly requested)
|
||||
if(validIP($serverName) || in_array($serverName,$AUTHORIZED_HOSTNAMES))
|
||||
{
|
||||
http_response_code(404);
|
||||
die();
|
||||
}
|
||||
|
||||
if(in_array($uriExt, $webExt) || empty($uriExt))
|
||||
{
|
||||
// Requested resource has an extension listed in $webExt
|
||||
// or no extension (index access to some folder incl. the root dir)
|
||||
$showPage = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Something else
|
||||
$showPage = false;
|
||||
}
|
||||
|
||||
// Handle incoming URI types
|
||||
if (!$showPage)
|
||||
{
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<script>window.close();</script></head>
|
||||
<body>
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
die();
|
||||
}
|
||||
|
||||
// Get Pi-hole version
|
||||
$piHoleVersion = exec('cd /etc/.pihole/ && git describe --tags --abbrev=0');
|
||||
|
||||
// Don't show the URI if it is the root directory
|
||||
if($uri == "/")
|
||||
{
|
||||
$uri = "";
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='UTF-8'/>
|
||||
<title>Website Blocked</title>
|
||||
<link rel='stylesheet' href='http://pi.hole/pihole/blockingpage.css'/>
|
||||
<link rel='shortcut icon' href='http://pi.hole/admin/img/favicon.png' type='image/png'/>
|
||||
<meta name='viewport' content='width=device-width,initial-scale=1.0,maximum-scale=1.0, user-scalable=no'/>
|
||||
<meta name='robots' content='noindex,nofollow'/>
|
||||
</head>
|
||||
<body id="body">
|
||||
<header>
|
||||
<h1><a href='/'>Website Blocked</a></h1>
|
||||
</header>
|
||||
<main>
|
||||
<div>Access to the following site has been blocked:<br/>
|
||||
<span class='pre msg'><?php echo $serverName.$uri; ?></span></div>
|
||||
<div>If you have an ongoing use for this website, please ask the owner of the Pi-hole in your network to have it whitelisted.</div>
|
||||
<input id="domain" type="hidden" value="<?php echo $serverName; ?>">
|
||||
<input id="quiet" type="hidden" value="yes">
|
||||
<button id="btnSearch" class="buttons blocked" type="button" style="visibility: hidden;"></button>
|
||||
This page is blocked because it is explicitly contained within the following block list(s):
|
||||
<pre id="output" style="width: 100%; height: 100%;" hidden="true"></pre><br/>
|
||||
<div class='buttons blocked'>
|
||||
<a class='safe33' href='javascript:history.back()'>Go back</a>
|
||||
<a class='safe33' id="whitelisting">Whitelist this page</a>
|
||||
<a class='safe33' href='javascript:window.close()'>Close window</a>
|
||||
</div>
|
||||
<div style="width: 98%; text-align: center; padding: 10px;" hidden="true" id="whitelistingform">
|
||||
<p>Note that whitelisting domains which are blocked using the wildcard method won't work.</p>
|
||||
<p>Password required!</p><br/>
|
||||
<form>
|
||||
<input name="list" type="hidden" value="white"><br/>
|
||||
Domain:<br/>
|
||||
<input name="domain" value="<?php echo $serverName ?>" disabled><br/><br/>
|
||||
Password:<br/>
|
||||
<input type="password" id="pw" name="pw"><br/><br/>
|
||||
<button class="buttons33 safe" id="btnAdd" type="button">Whitelist</button>
|
||||
</form><br/>
|
||||
<pre id="whitelistingoutput" style="width: 100%; height: 100%; padding: 5px;" hidden="true"></pre><br/>
|
||||
</div>
|
||||
</main>
|
||||
<footer>Generated <?php echo date('D g:i A, M d'); ?> by Pi-hole <?php echo $piHoleVersion; ?></footer>
|
||||
<script src="http://pi.hole/admin/scripts/vendor/jquery.min.js"></script>
|
||||
<script>
|
||||
// Create event for when the output is appended to
|
||||
(function($) {
|
||||
var origAppend = $.fn.append;
|
||||
|
||||
$.fn.append = function () {
|
||||
return origAppend.apply(this, arguments).trigger("append");
|
||||
};
|
||||
})(jQuery);
|
||||
</script>
|
||||
<script src="http://pi.hole/admin/scripts/pi-hole/js/queryads.js"></script>
|
||||
<script>
|
||||
function inIframe () {
|
||||
try {
|
||||
return window.self !== window.top;
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to detect if page is loaded within iframe
|
||||
if(inIframe())
|
||||
{
|
||||
// Within iframe
|
||||
// hide content of page
|
||||
$('#body').hide();
|
||||
// remove background
|
||||
document.body.style.backgroundImage = "none";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Query adlists
|
||||
$( "#btnSearch" ).click();
|
||||
}
|
||||
|
||||
$( "#whitelisting" ).on( "click", function(){ $( "#whitelistingform" ).removeAttr( "hidden" ); });
|
||||
|
||||
// Remove whitelist functionality if the domain was blocked because of a wildcard
|
||||
$( "#output" ).bind("append", function(){
|
||||
if($( "#output" ).contents()[0].data.indexOf("Wildcard blocking") !== -1)
|
||||
{
|
||||
$( "#whitelisting" ).hide();
|
||||
$( "#whitelistingform" ).hide();
|
||||
}
|
||||
});
|
||||
|
||||
function add() {
|
||||
var domain = $("#domain");
|
||||
var pw = $("#pw");
|
||||
if(domain.val().length === 0){
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: "/admin/scripts/pi-hole/php/add.php",
|
||||
method: "post",
|
||||
data: {"domain":domain.val(), "list":"white", "pw":pw.val()},
|
||||
success: function(response) {
|
||||
$( "#whitelistingoutput" ).removeAttr( "hidden" );
|
||||
if(response.indexOf("Pi-hole blocking") !== -1)
|
||||
{
|
||||
// Reload page after 5 seconds
|
||||
setTimeout(function(){window.location.reload(1);}, 5000);
|
||||
$( "#whitelistingoutput" ).html("---> Success <---<br/>You may have to flush your DNS cache");
|
||||
}
|
||||
else
|
||||
{
|
||||
$( "#whitelistingoutput" ).html("---> "+response+" <---");
|
||||
}
|
||||
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
$( "#whitelistingoutput" ).removeAttr( "hidden" );
|
||||
$( "#whitelistingoutput" ).html("---> Unknown Error <---");
|
||||
}
|
||||
});
|
||||
}
|
||||
// Handle enter button for adding domains
|
||||
$(document).keypress(function(e) {
|
||||
if(e.which === 13 && $("#pw").is(":focus")) {
|
||||
add();
|
||||
}
|
||||
});
|
||||
|
||||
// Handle buttons
|
||||
$("#btnAdd").on("click", function() {
|
||||
add();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -1,47 +0,0 @@
|
||||
server.modules = (
|
||||
"mod_expire",
|
||||
"mod_compress",
|
||||
"mod_redirect",
|
||||
"mod_setenv",
|
||||
"mod_rewrite"
|
||||
)
|
||||
|
||||
server.document-root = "/var/www/html"
|
||||
server.error-handler-404 = "pihole/index.html"
|
||||
server.upload-dirs = ( "/var/cache/lighttpd/uploads" )
|
||||
server.errorlog = "/var/log/lighttpd/error.log"
|
||||
server.pid-file = "/var/run/lighttpd.pid"
|
||||
server.username = "www-data"
|
||||
server.groupname = "www-data"
|
||||
server.port = 80
|
||||
|
||||
|
||||
index-file.names = ( "index.php", "index.html", "index.lighttpd.html" )
|
||||
url.access-deny = ( "~", ".inc" )
|
||||
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
|
||||
|
||||
compress.cache-dir = "/var/cache/lighttpd/compress/"
|
||||
compress.filetype = ( "application/javascript", "text/css", "text/html", "text/plain" )
|
||||
|
||||
# default listening port for IPv6 falls back to the IPv4 port
|
||||
include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port
|
||||
include_shell "/usr/share/lighttpd/create-mime.assign.pl"
|
||||
include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
|
||||
|
||||
# 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!" )
|
||||
}
|
||||
|
||||
# If the URL does not start with /admin, then it is a query for an ad domain
|
||||
$HTTP["url"] =~ "^(?!/admin)/.*" {
|
||||
# Create a response header for debugging using curl -I
|
||||
setenv.add-response-header = ( "X-Pi-hole" => "A black hole for Internet advertisements." )
|
||||
|
||||
# Set the cache to 1 day for better performance
|
||||
expire.url = ("" => "access plus 1 days")
|
||||
|
||||
# Send the query into the black hole
|
||||
url.rewrite = (".*" => "pihole/index.html" )
|
||||
}
|
81
advanced/lighttpd.conf.debian
Normal file
81
advanced/lighttpd.conf.debian
Normal file
@@ -0,0 +1,81 @@
|
||||
# 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 #
|
||||
# #
|
||||
# CHANGES SHOULD BE MADE IN A SEPERATE CONFIG FILE: #
|
||||
# /etc/lighttpd/external.conf #
|
||||
###############################################################################
|
||||
|
||||
server.modules = (
|
||||
"mod_access",
|
||||
"mod_accesslog",
|
||||
"mod_auth",
|
||||
"mod_expire",
|
||||
"mod_compress",
|
||||
"mod_redirect",
|
||||
"mod_setenv",
|
||||
"mod_rewrite"
|
||||
)
|
||||
|
||||
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.log"
|
||||
server.pid-file = "/var/run/lighttpd.pid"
|
||||
server.username = "www-data"
|
||||
server.groupname = "www-data"
|
||||
server.port = 80
|
||||
accesslog.filename = "/var/log/lighttpd/access.log"
|
||||
accesslog.format = "%{%s}t|%V|%r|%s|%b"
|
||||
|
||||
|
||||
index-file.names = ( "index.php", "index.html", "index.lighttpd.html" )
|
||||
url.access-deny = ( "~", ".inc" )
|
||||
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
|
||||
|
||||
compress.cache-dir = "/var/cache/lighttpd/compress/"
|
||||
compress.filetype = ( "application/javascript", "text/css", "text/html", "text/plain" )
|
||||
|
||||
# default listening port for IPv6 falls back to the IPv4 port
|
||||
include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port
|
||||
include_shell "/usr/share/lighttpd/create-mime.assign.pl"
|
||||
include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
|
||||
|
||||
# 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"
|
||||
)
|
||||
}
|
||||
|
||||
# Rewite js requests, must be out of $HTTP block due to bug #2526
|
||||
url.rewrite = ( "^(?!/admin/).*\.js$" => "pihole/index.js" )
|
||||
|
||||
# If the URL does not start with /admin, then it is a query for an ad domain
|
||||
$HTTP["url"] =~ "^(?!/admin)/.*" {
|
||||
# Create a response header for debugging using curl -I
|
||||
setenv.add-response-header = ( "X-Pi-hole" => "A black hole for Internet advertisements." )
|
||||
}
|
||||
|
||||
# Entering just "pi.hole" into a browser redirects to "pi.hole/admin/"
|
||||
$HTTP["host"] == "pi.hole" {
|
||||
$HTTP["url"] == "/" {
|
||||
url.redirect = ( "" => "/admin/" )
|
||||
}
|
||||
}
|
||||
|
||||
# Add user chosen options held in external file
|
||||
include_shell "cat external.conf 2>/dev/null"
|
98
advanced/lighttpd.conf.fedora
Normal file
98
advanced/lighttpd.conf.fedora
Normal file
@@ -0,0 +1,98 @@
|
||||
# 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 #
|
||||
# #
|
||||
# CHANGES SHOULD BE MADE IN A SEPERATE CONFIG FILE: #
|
||||
# /etc/lighttpd/external.conf #
|
||||
###############################################################################
|
||||
|
||||
server.modules = (
|
||||
"mod_access",
|
||||
"mod_auth",
|
||||
"mod_fastcgi",
|
||||
"mod_accesslog",
|
||||
"mod_expire",
|
||||
"mod_compress",
|
||||
"mod_redirect",
|
||||
"mod_setenv",
|
||||
"mod_rewrite"
|
||||
)
|
||||
|
||||
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.log"
|
||||
server.pid-file = "/var/run/lighttpd.pid"
|
||||
server.username = "lighttpd"
|
||||
server.groupname = "lighttpd"
|
||||
server.port = 80
|
||||
accesslog.filename = "/var/log/lighttpd/access.log"
|
||||
accesslog.format = "%{%s}t|%V|%r|%s|%b"
|
||||
|
||||
|
||||
index-file.names = ( "index.php", "index.html", "index.lighttpd.html" )
|
||||
url.access-deny = ( "~", ".inc" )
|
||||
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
|
||||
|
||||
compress.cache-dir = "/var/cache/lighttpd/compress/"
|
||||
compress.filetype = ( "application/javascript", "text/css", "text/html", "text/plain" )
|
||||
|
||||
mimetype.assign = ( ".png" => "image/png",
|
||||
".jpg" => "image/jpeg",
|
||||
".jpeg" => "image/jpeg",
|
||||
".html" => "text/html",
|
||||
".css" => "text/css; charset=utf-8",
|
||||
".js" => "application/javascript",
|
||||
".json" => "application/json",
|
||||
".txt" => "text/plain",
|
||||
".svg" => "image/svg+xml" )
|
||||
|
||||
# default listening port for IPv6 falls back to the IPv4 port
|
||||
#include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port
|
||||
#include_shell "/usr/share/lighttpd/create-mime.assign.pl"
|
||||
#include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
|
||||
|
||||
fastcgi.server = ( ".php" =>
|
||||
( "localhost" =>
|
||||
(
|
||||
"socket" => "/tmp/php-fastcgi.socket",
|
||||
"bin-path" => "/usr/bin/php-cgi"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
# 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!" )
|
||||
}
|
||||
|
||||
# Rewite js requests, must be out of $HTTP block due to bug #2526
|
||||
url.rewrite = ( "^(?!/admin/).*\.js$" => "pihole/index.js" )
|
||||
|
||||
# If the URL does not start with /admin, then it is a query for an ad domain
|
||||
$HTTP["url"] =~ "^(?!/admin)/.*" {
|
||||
# Create a response header for debugging using curl -I
|
||||
setenv.add-response-header = ( "X-Pi-hole" => "A black hole for Internet advertisements." )
|
||||
}
|
||||
|
||||
# Entering just "pi.hole" into a browser redirects to "pi.hole/admin/"
|
||||
$HTTP["host"] == "pi.hole" {
|
||||
$HTTP["url"] == "/" {
|
||||
url.redirect = ( "" => "/admin/" )
|
||||
}
|
||||
}
|
||||
|
||||
# Add user chosen options held in external file
|
||||
include_shell "cat external.conf 2>/dev/null"
|
21
advanced/logrotate
Normal file
21
advanced/logrotate
Normal file
@@ -0,0 +1,21 @@
|
||||
/var/log/pihole.log {
|
||||
# su #
|
||||
daily
|
||||
copytruncate
|
||||
rotate 5
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
nomail
|
||||
}
|
||||
|
||||
/var/log/pihole-FTL.log {
|
||||
# su #
|
||||
weekly
|
||||
copytruncate
|
||||
rotate 3
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
nomail
|
||||
}
|
80
advanced/pihole-FTL.service
Normal file
80
advanced/pihole-FTL.service
Normal file
@@ -0,0 +1,80 @@
|
||||
#!/bin/bash
|
||||
### BEGIN INIT INFO
|
||||
# Provides: pihole-FTL
|
||||
# Required-Start: $remote_fs $syslog
|
||||
# Required-Stop: $remote_fs $syslog
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: pihole-FTL daemon
|
||||
# Description: Enable service provided by pihole-FTL daemon
|
||||
### END INIT INFO
|
||||
|
||||
FTLUSER=pihole
|
||||
PIDFILE=/var/run/pihole-FTL.pid
|
||||
|
||||
get_pid() {
|
||||
pidof "pihole-FTL"
|
||||
}
|
||||
|
||||
is_running() {
|
||||
ps "$(get_pid)" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
# Start the service
|
||||
start() {
|
||||
if is_running; then
|
||||
echo "pihole-FTL is already running"
|
||||
else
|
||||
touch /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port
|
||||
chown pihole:pihole /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port /etc/pihole
|
||||
chmod 0644 /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port
|
||||
su -s /bin/sh -c "/usr/bin/pihole-FTL" "$FTLUSER"
|
||||
echo
|
||||
fi
|
||||
}
|
||||
|
||||
# Stop the service
|
||||
stop() {
|
||||
if is_running; then
|
||||
kill "$(get_pid)"
|
||||
for i in {1..5}; do
|
||||
if ! is_running; then
|
||||
break
|
||||
fi
|
||||
|
||||
echo -n "."
|
||||
sleep 1
|
||||
done
|
||||
echo
|
||||
|
||||
if is_running; then
|
||||
echo "Not stopped; may still be shutting down or shutdown may have failed, killing now"
|
||||
kill -9 "$(get_pid)"
|
||||
exit 1
|
||||
else
|
||||
echo "Stopped"
|
||||
fi
|
||||
else
|
||||
echo "Not running"
|
||||
fi
|
||||
echo
|
||||
}
|
||||
|
||||
### main logic ###
|
||||
case "$1" in
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
status)
|
||||
status pihole-FTL
|
||||
;;
|
||||
start|restart|reload|condrestart)
|
||||
stop
|
||||
start
|
||||
;;
|
||||
*)
|
||||
echo $"Usage: $0 {start|stop|restart|reload|status}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit 0
|
@@ -1,26 +1,30 @@
|
||||
# /etc/crontab: system-wide crontab
|
||||
# Unlike any other crontab you don't have to run the `crontab'
|
||||
# command to install the new version when you edit this file
|
||||
# and files in /etc/cron.d. These files also have username fields,
|
||||
# that none of the other crontabs do.
|
||||
|
||||
SHELL=/bin/sh
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
|
||||
# m h dom mon dow user command
|
||||
17 * * * * root cd / && run-parts --report /etc/cron.hourly
|
||||
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
|
||||
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
|
||||
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
|
||||
# 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.
|
||||
#
|
||||
# Updates ad sources every week
|
||||
#
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
#
|
||||
#
|
||||
#
|
||||
# This file is under source-control of the Pi-hole installation and update
|
||||
# scripts, any changes made to this file will be overwritten when the softare
|
||||
# is updated or re-installed. Please make any changes to the appropriate crontab
|
||||
# or other cron file snippets.
|
||||
|
||||
# Pi-hole: Update the ad sources once a week on Sunday at 01:59
|
||||
# Download any updates from the ad lists
|
||||
59 1 * * 7 root /usr/local/bin/gravity.sh
|
||||
# Download any updates from the adlists
|
||||
59 1 * * 7 root PATH="$PATH:/usr/local/bin/" pihole updateGravity
|
||||
|
||||
# Pi-hole: Parse the log file before it is flushed and save the stats to a database
|
||||
# This will be used for a historical view of your Pi-hole's performance
|
||||
#50 11 * * * root /usr/local/bin/dailyLog.sh
|
||||
# Pi-hole: Update Pi-hole! Uncomment to enable auto update
|
||||
#30 2 * * 7 root PATH="$PATH:/usr/local/bin/" pihole updatePihole
|
||||
|
||||
# Pi-hole: Flush the log daily at 11:58 so it doesn't get out of control
|
||||
# Stats will be viewable in the Web interface thanks to the cron job above
|
||||
58 11 * * * root /usr/local/bin/piholeLogFlush.sh
|
||||
# Pi-hole: Flush the log daily at 00:00
|
||||
# The flush script will use logrotate if available
|
||||
# parameter "once": logrotate only once (default is twice)
|
||||
# parameter "quiet": don't print messages
|
||||
00 00 * * * root PATH="$PATH:/usr/local/bin/" pihole flush once quiet
|
||||
|
||||
@reboot root /usr/sbin/logrotate /etc/pihole/logrotate
|
||||
|
9
advanced/pihole.sudo
Normal file
9
advanced/pihole.sudo
Normal file
@@ -0,0 +1,9 @@
|
||||
# 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.
|
||||
#
|
||||
# Allows the WebUI to use Pi-hole commands
|
||||
#
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
#
|
File diff suppressed because it is too large
Load Diff
196
automated install/uninstall.sh
Normal file → Executable file
196
automated install/uninstall.sh
Normal file → Executable file
@@ -1,19 +1,181 @@
|
||||
#!/bin/bash
|
||||
# Completely uninstalls the Pi-hole
|
||||
#!/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.
|
||||
#
|
||||
# Completely uninstalls Pi-hole
|
||||
#
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
|
||||
|
||||
# Must be root to uninstall
|
||||
if [[ ${EUID} -eq 0 ]]; then
|
||||
echo "::: You are root."
|
||||
else
|
||||
echo "::: Sudo will be used for the uninstall."
|
||||
# Check if it is actually installed
|
||||
# If it isn't, exit because the unnstall cannot complete
|
||||
if [ -x "$(command -v sudo)" ]; then
|
||||
export SUDO="sudo"
|
||||
else
|
||||
echo "::: Please install sudo or run this as root."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Compatability
|
||||
if [ -x "$(command -v rpm)" ]; then
|
||||
# Fedora Family
|
||||
if [ -x "$(command -v dnf)" ]; then
|
||||
PKG_MANAGER="dnf"
|
||||
else
|
||||
PKG_MANAGER="yum"
|
||||
fi
|
||||
PKG_REMOVE="${PKG_MANAGER} remove -y"
|
||||
PIHOLE_DEPS=( bind-utils bc dnsmasq lighttpd lighttpd-fastcgi php-common git curl unzip wget findutils )
|
||||
package_check() {
|
||||
rpm -qa | grep ^$1- > /dev/null
|
||||
}
|
||||
package_cleanup() {
|
||||
${SUDO} ${PKG_MANAGER} -y autoremove
|
||||
}
|
||||
elif [ -x "$(command -v apt-get)" ]; then
|
||||
# Debian Family
|
||||
PKG_MANAGER="apt-get"
|
||||
PKG_REMOVE="${PKG_MANAGER} -y remove --purge"
|
||||
PIHOLE_DEPS=( dnsutils bc dnsmasq lighttpd php5-common git curl unzip wget )
|
||||
package_check() {
|
||||
dpkg-query -W -f='${Status}' "$1" 2>/dev/null | grep -c "ok installed"
|
||||
}
|
||||
package_cleanup() {
|
||||
${SUDO} ${PKG_MANAGER} -y autoremove
|
||||
${SUDO} ${PKG_MANAGER} -y autoclean
|
||||
}
|
||||
else
|
||||
echo "OS distribution not supported"
|
||||
exit
|
||||
fi
|
||||
|
||||
spinner() {
|
||||
local pid=$1
|
||||
local delay=0.50
|
||||
local spinstr='/-\|'
|
||||
while [ "$(ps a | awk '{print $1}' | grep "${pid}")" ]; do
|
||||
local temp=${spinstr#?}
|
||||
printf " [%c] " "${spinstr}"
|
||||
local spinstr=${temp}${spinstr%"$temp}"}
|
||||
sleep ${delay}
|
||||
printf "\b\b\b\b\b\b"
|
||||
done
|
||||
printf " \b\b\b\b"
|
||||
}
|
||||
|
||||
removeAndPurge() {
|
||||
# Purge dependencies
|
||||
echo ":::"
|
||||
for i in "${PIHOLE_DEPS[@]}"; do
|
||||
package_check ${i} > /dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
while true; do
|
||||
read -rp "::: Do you wish to remove ${i} from your system? [y/n]: " yn
|
||||
case ${yn} in
|
||||
[Yy]* ) printf ":::\tRemoving %s..." "${i}"; ${SUDO} ${PKG_REMOVE} "${i}" &> /dev/null & spinner $!; printf "done!\n"; break;;
|
||||
[Nn]* ) printf ":::\tSkipping %s\n" "${i}"; break;;
|
||||
* ) printf "::: You must answer yes or no!\n";;
|
||||
esac
|
||||
done
|
||||
else
|
||||
printf ":::\tPackage %s not installed... Not removing.\n" "${i}"
|
||||
fi
|
||||
done
|
||||
|
||||
# Remove dependency config files
|
||||
echo "::: Removing dnsmasq config files..."
|
||||
${SUDO} rm /etc/dnsmasq.conf /etc/dnsmasq.conf.orig /etc/dnsmasq.d/01-pihole.conf &> /dev/null
|
||||
|
||||
# Take care of any additional package cleaning
|
||||
printf "::: Auto removing & cleaning remaining dependencies..."
|
||||
package_cleanup &> /dev/null & spinner $!; printf "done!\n";
|
||||
|
||||
# Call removeNoPurge to remove PiHole specific files
|
||||
removeNoPurge
|
||||
}
|
||||
|
||||
removeNoPurge() {
|
||||
echo ":::"
|
||||
# Only web directories/files that are created by pihole should be removed.
|
||||
echo "::: Removing the Pi-hole Web server files..."
|
||||
${SUDO} rm -rf /var/www/html/admin &> /dev/null
|
||||
${SUDO} rm -rf /var/www/html/pihole &> /dev/null
|
||||
${SUDO} rm /var/www/html/index.lighttpd.orig &> /dev/null
|
||||
|
||||
# If the web directory is empty after removing these files, then the parent html folder can be removed.
|
||||
if [ -d "/var/www/html" ]; then
|
||||
if [[ ! "$(ls -A /var/www/html)" ]]; then
|
||||
${SUDO} rm -rf /var/www/html &> /dev/null
|
||||
fi
|
||||
fi
|
||||
|
||||
# Attempt to preserve backwards compatibility with older versions
|
||||
# to guarantee no additional changes were made to /etc/crontab after
|
||||
# the installation of pihole, /etc/crontab.pihole should be permanently
|
||||
# preserved.
|
||||
if [[ -f /etc/crontab.orig ]]; then
|
||||
echo "::: Initial Pi-hole cron detected. Restoring the default system cron..."
|
||||
${SUDO} mv /etc/crontab /etc/crontab.pihole
|
||||
${SUDO} mv /etc/crontab.orig /etc/crontab
|
||||
${SUDO} service cron restart
|
||||
fi
|
||||
|
||||
# Attempt to preserve backwards compatibility with older versions
|
||||
if [[ -f /etc/cron.d/pihole ]];then
|
||||
echo "::: Removing cron.d/pihole..."
|
||||
${SUDO} rm /etc/cron.d/pihole &> /dev/null
|
||||
fi
|
||||
|
||||
echo "::: Removing config files and scripts..."
|
||||
package_check lighttpd > /dev/null
|
||||
if [ $? -eq 1 ]; then
|
||||
${SUDO} rm -rf /etc/lighttpd/ &> /dev/null
|
||||
else
|
||||
if [ -f /etc/lighttpd/lighttpd.conf.orig ]; then
|
||||
${SUDO} mv /etc/lighttpd/lighttpd.conf.orig /etc/lighttpd/lighttpd.conf
|
||||
fi
|
||||
fi
|
||||
|
||||
${SUDO} rm /etc/dnsmasq.d/adList.conf &> /dev/null
|
||||
${SUDO} rm /etc/dnsmasq.d/01-pihole.conf &> /dev/null
|
||||
${SUDO} rm -rf /var/log/*pihole* &> /dev/null
|
||||
${SUDO} rm -rf /etc/pihole/ &> /dev/null
|
||||
${SUDO} rm -rf /etc/.pihole/ &> /dev/null
|
||||
${SUDO} rm -rf /opt/pihole/ &> /dev/null
|
||||
${SUDO} rm /usr/local/bin/pihole &> /dev/null
|
||||
${SUDO} rm /etc/bash_completion.d/pihole &> /dev/null
|
||||
${SUDO} rm /etc/sudoers.d/pihole &> /dev/null
|
||||
|
||||
# If the pihole user exists, then remove
|
||||
if id "pihole" >/dev/null 2>&1; then
|
||||
echo "::: Removing pihole user..."
|
||||
${SUDO} userdel -r pihole
|
||||
fi
|
||||
|
||||
echo ":::"
|
||||
printf "::: Finished removing PiHole from your system. Sorry to see you go!\n"
|
||||
printf "::: Reach out to us at https://github.com/pi-hole/pi-hole/issues if you need help\n"
|
||||
printf "::: Reinstall by simpling running\n:::\n:::\tcurl -sSL https://install.pi-hole.net | bash\n:::\n::: at any time!\n:::\n"
|
||||
printf "::: PLEASE RESET YOUR DNS ON YOUR ROUTER/CLIENTS TO RESTORE INTERNET CONNECTIVITY!\n"
|
||||
}
|
||||
|
||||
######### SCRIPT ###########
|
||||
sudo apt-get -y remove --purge dnsutils bc toilet
|
||||
sudo apt-get -y remove --purge dnsmasq
|
||||
sudo apt-get -y remove --purge lighttpd php5-common php5-cgi php5
|
||||
sudo rm -rf /var/www/html
|
||||
sudo rm /etc/dnsmasq.conf /etc/dnsmasq.conf.orig
|
||||
sudo rm /etc/crontab
|
||||
sudo mv /etc/crontab.orig /etc/crontab
|
||||
sudo rm /etc/dnsmasq.conf
|
||||
sudo rm -rf /etc/lighttpd/
|
||||
sudo rm /var/log/pihole.log
|
||||
sudo rm /usr/local/bin/gravity.sh
|
||||
sudo rm /usr/local/bin/chronometer.sh
|
||||
sudo rm /usr/local/bin/whitelist.sh
|
||||
sudo rm /usr/local/bin/piholeLogFlush.sh
|
||||
sudo rm -rf /etc/pihole/
|
||||
echo "::: Preparing to remove packages, be sure that each may be safely removed depending on your operating system."
|
||||
echo "::: (SAFE TO REMOVE ALL ON RASPBIAN)"
|
||||
while true; do
|
||||
read -rp "::: Do you wish to purge PiHole's dependencies from your OS? (You will be prompted for each package) [y/n]: " yn
|
||||
case ${yn} in
|
||||
[Yy]* ) removeAndPurge; break;;
|
||||
|
||||
[Nn]* ) removeNoPurge; break;;
|
||||
esac
|
||||
done
|
||||
|
@@ -1,3 +1,14 @@
|
||||
# Pi-hole: A black hole for Internet advertisements
|
||||
# (c) 2015, 2016 by Jacob Salmela
|
||||
# Network-wide ad blocking via your Raspberry Pi
|
||||
# http://pi-hole.net
|
||||
# Lighttpd config file for Pi-hole
|
||||
#
|
||||
# Pi-hole is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
server.modules = (
|
||||
"mod_access",
|
||||
"mod_alias",
|
||||
@@ -27,6 +38,6 @@ include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port
|
||||
include_shell "/usr/share/lighttpd/create-mime.assign.pl"
|
||||
include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
|
||||
|
||||
$HTTP["host"] =~ "ads.hulu.com|ads-v-darwin.hulu.com" {
|
||||
$HTTP["host"] =~ "ads.hulu.com|ads-v-darwin.hulu.com|ads-e-darwin.hulu.com" {
|
||||
url.redirect = ( ".*" => "http://192.168.1.101:8200/MediaItems/19.mov")
|
||||
}
|
||||
|
@@ -1,6 +1,17 @@
|
||||
# Pi-hole: A black hole for Internet advertisements
|
||||
# (c) 2015, 2016 by Jacob Salmela
|
||||
# Network-wide ad blocking via your Raspberry Pi
|
||||
# http://pi-hole.net
|
||||
# MiniDLNA config file for Pi-hole
|
||||
#
|
||||
# Pi-hole is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
media_dir=V,/var/lib/minidlna/videos/
|
||||
port=8200
|
||||
friendly_name=pihole
|
||||
serial=12345678
|
||||
model_number=1
|
||||
inotify=yes
|
||||
inotify=yes
|
||||
|
617
gravity.sh
617
gravity.sh
@@ -1,236 +1,459 @@
|
||||
#!/usr/bin/env bash
|
||||
# Pi-hole: A black hole for Internet advertisements
|
||||
# (c) 2015 by Jacob Salmela GPL 2.0
|
||||
# Network-wide ad blocking via your Raspberry Pi
|
||||
# http://pi-hole.net
|
||||
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||
# Network-wide ad blocking via your own hardware.
|
||||
#
|
||||
# Compiles a list of ad-serving domains by downloading them from multiple sources
|
||||
piholeIPfile=/tmp/piholeIP
|
||||
if [[ -f $piholeIPfile ]];then
|
||||
# If the file exists, it means it was exported from the installation script and we should use that value instead of detecting it in this script
|
||||
piholeIP=$(cat $piholeIPfile)
|
||||
rm $piholeIPfile
|
||||
#
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
|
||||
|
||||
# Run this script as root or under sudo
|
||||
echo ":::"
|
||||
|
||||
helpFunc() {
|
||||
cat << EOM
|
||||
::: Pull in domains from adlists
|
||||
:::
|
||||
::: Usage: pihole -g
|
||||
:::
|
||||
::: Options:
|
||||
::: -f, --force Force lists to be downloaded, even if they don't need updating.
|
||||
::: -h, --help Show this help dialog
|
||||
EOM
|
||||
exit 0
|
||||
}
|
||||
|
||||
PIHOLE_COMMAND="/usr/local/bin/pihole"
|
||||
|
||||
adListFile=/etc/pihole/adlists.list
|
||||
adListDefault=/etc/pihole/adlists.default #being deprecated
|
||||
adListRepoDefault=/etc/.pihole/adlists.default
|
||||
whitelistScript="${PIHOLE_COMMAND} -w"
|
||||
whitelistFile=/etc/pihole/whitelist.txt
|
||||
blacklistFile=/etc/pihole/blacklist.txt
|
||||
readonly wildcardlist="/etc/dnsmasq.d/03-pihole-wildcard.conf"
|
||||
|
||||
#Source the setupVars from install script for the IP
|
||||
setupVars=/etc/pihole/setupVars.conf
|
||||
if [[ -f ${setupVars} ]];then
|
||||
. /etc/pihole/setupVars.conf
|
||||
else
|
||||
# Otherwise, the IP address can be taken directly from the machine, which will happen when the script is run by the user and not the installation script
|
||||
IPv4dev=$(ip route get 8.8.8.8 | awk '{print $5}')
|
||||
piholeIPCIDR=$(ip -o -f inet addr show dev $IPv4dev | awk '{print $4}')
|
||||
piholeIP=${piholeIPCIDR%/*}
|
||||
echo "::: WARNING: /etc/pihole/setupVars.conf missing. Possible installation failure."
|
||||
echo "::: Please run 'pihole -r', and choose the 'reconfigure' option to reconfigure."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Ad-list sources--one per line in single quotes
|
||||
# The mahakala source is commented out due to many users having issues with it blocking legitimate domains. Uncomment at your own risk
|
||||
sources=('https://adaway.org/hosts.txt'
|
||||
'http://adblock.gjtech.net/?format=unix-hosts'
|
||||
#'http://adblock.mahakala.is/'
|
||||
'http://hosts-file.net/ad_servers.txt'
|
||||
'http://www.malwaredomainlist.com/hostslist/hosts.txt'
|
||||
'http://pgl.yoyo.org/adservers/serverlist.php?'
|
||||
'http://someonewhocares.org/hosts/hosts'
|
||||
'http://winhelp2002.mvps.org/hosts.txt')
|
||||
#Remove the /* from the end of the IPv4addr.
|
||||
IPV4_ADDRESS=${IPV4_ADDRESS%/*}
|
||||
IPV6_ADDRESS=${IPV6_ADDRESS}
|
||||
|
||||
# Variables for various stages of downloading and formatting the list
|
||||
basename=pihole
|
||||
piholeDir=/etc/$basename
|
||||
adList=$piholeDir/gravity.list
|
||||
blacklist=$piholeDir/blacklist.txt
|
||||
whitelist=$piholeDir/whitelist.txt
|
||||
latentWhitelist=$piholeDir/latentWhitelist.txt
|
||||
piholeDir=/etc/${basename}
|
||||
adList=${piholeDir}/gravity.list
|
||||
blackList=${piholeDir}/black.list
|
||||
localList=${piholeDir}/local.list
|
||||
justDomainsExtension=domains
|
||||
matter=$basename.0.matter.txt
|
||||
andLight=$basename.1.andLight.txt
|
||||
supernova=$basename.2.supernova.txt
|
||||
eventHorizon=$basename.3.eventHorizon.txt
|
||||
accretionDisc=$basename.4.accretionDisc.txt
|
||||
eyeOfTheNeedle=$basename.5.wormhole.txt
|
||||
matterAndLight=${basename}.0.matterandlight.txt
|
||||
supernova=${basename}.1.supernova.txt
|
||||
preEventHorizon=list.preEventHorizon
|
||||
eventHorizon=${basename}.2.supernova.txt
|
||||
accretionDisc=${basename}.3.accretionDisc.txt
|
||||
|
||||
# After setting defaults, check if there's local overrides
|
||||
if [[ -r $piholeDir/pihole.conf ]];then
|
||||
echo "** Local calibration requested..."
|
||||
. $piholeDir/pihole.conf
|
||||
skipDownload=false
|
||||
|
||||
# Warn users still using pihole.conf that it no longer has any effect (I imagine about 2 people use it)
|
||||
if [[ -r ${piholeDir}/pihole.conf ]]; then
|
||||
echo "::: pihole.conf file no longer supported. Over-rides in this file are ignored."
|
||||
fi
|
||||
|
||||
###########################
|
||||
# collapse - begin formation of pihole
|
||||
function gravity_collapse() {
|
||||
echo "** Neutrino emissions detected..."
|
||||
gravity_collapse() {
|
||||
|
||||
# Create the pihole resource directory if it doesn't exist. Future files will be stored here
|
||||
if [[ -d $piholeDir ]];then
|
||||
# Temporary hack to allow non-root access to pihole directory
|
||||
# Will update later, needed for existing installs, new installs should
|
||||
# create this directory as non-root
|
||||
sudo chmod 777 $piholeDir
|
||||
find "$piholeDir" -type f -exec sudo chmod 666 {} \;
|
||||
else
|
||||
echo "** Creating pihole directory..."
|
||||
mkdir $piholeDir
|
||||
fi
|
||||
#New Logic:
|
||||
# Does /etc/pihole/adlists.list exist? If so leave it alone
|
||||
# If not, cp /etc/.pihole/adlists.default /etc/pihole/adlists.list
|
||||
# Read from adlists.list
|
||||
|
||||
#The following two blocks will sort out any missing adlists in the /etc/pihole directory, and remove legacy adlists.default
|
||||
if [ -f ${adListDefault} ] && [ -f ${adListFile} ]; then
|
||||
rm ${adListDefault}
|
||||
fi
|
||||
|
||||
if [ ! -f ${adListFile} ]; then
|
||||
cp ${adListRepoDefault} ${adListFile}
|
||||
fi
|
||||
|
||||
echo "::: Neutrino emissions detected..."
|
||||
echo ":::"
|
||||
echo -n "::: Pulling source lists into range..."
|
||||
sources=()
|
||||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||
#Do not read commented out or blank lines
|
||||
if [[ ${line} = \#* ]] || [[ ! ${line} ]]; then
|
||||
echo "" > /dev/null
|
||||
else
|
||||
sources+=(${line})
|
||||
fi
|
||||
done < ${adListFile}
|
||||
echo " done!"
|
||||
}
|
||||
|
||||
# patternCheck - check to see if curl downloaded any new files, and then process those
|
||||
# files so they are in host format.
|
||||
function gravity_patternCheck() {
|
||||
patternBuffer=$1
|
||||
# check if the patternbuffer is a non-zero length file
|
||||
if [[ -s "$patternBuffer" ]];then
|
||||
# Some of the blocklists are copyright, they need to be downloaded
|
||||
# and stored as is. They can be processed for content after they
|
||||
# have been saved.
|
||||
cp $patternBuffer $saveLocation
|
||||
echo "Done."
|
||||
else
|
||||
# curl didn't download any host files, probably because of the date check
|
||||
echo "Transporter logic detected no changes, pattern skipped..."
|
||||
# patternCheck - check to see if curl downloaded any new files.
|
||||
gravity_patternCheck() {
|
||||
patternBuffer=$1
|
||||
success=$2
|
||||
error=$3
|
||||
if [ $success = true ]; then
|
||||
# check if download was successful but list has not been modified
|
||||
if [ "${error}" == "304" ]; then
|
||||
echo "::: No changes detected, transport skipped!"
|
||||
# check if the patternbuffer is a non-zero length file
|
||||
elif [[ -s "${patternBuffer}" ]]; then
|
||||
# Some of the blocklists are copyright, they need to be downloaded
|
||||
# and stored as is. They can be processed for content after they
|
||||
# have been saved.
|
||||
mv "${patternBuffer}" "${saveLocation}"
|
||||
echo "::: List updated, transport successful!"
|
||||
else
|
||||
# Empty file -> use previously downloaded list
|
||||
echo "::: Received empty file, using cached one (list not updated!)"
|
||||
fi
|
||||
else
|
||||
# check if cached list exists
|
||||
if [[ -r "${saveLocation}" ]]; then
|
||||
echo "::: List download failed, using cached list (list not updated!)"
|
||||
else
|
||||
echo "::: Download failed and no cached list available (list will not be considered)"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# transport - curl the specified url with any needed command extentions
|
||||
gravity_transport() {
|
||||
url=$1
|
||||
cmd_ext=$2
|
||||
agent=$3
|
||||
|
||||
# tmp file, so we don't have to store the (long!) lists in RAM
|
||||
patternBuffer=$(mktemp)
|
||||
heisenbergCompensator=""
|
||||
if [[ -r ${saveLocation} ]]; then
|
||||
# if domain has been saved, add file for date check to only download newer
|
||||
heisenbergCompensator="-z ${saveLocation}"
|
||||
fi
|
||||
|
||||
# Silently curl url
|
||||
err=$(curl -s -L ${cmd_ext} ${heisenbergCompensator} -w %{http_code} -A "${agent}" ${url} -o ${patternBuffer})
|
||||
|
||||
echo " done"
|
||||
# Analyze http response
|
||||
echo -n "::: Status: "
|
||||
case "$err" in
|
||||
"200" ) echo "Success (OK)"; success=true;;
|
||||
"304" ) echo "Not modified"; success=true;;
|
||||
"403" ) echo "Forbidden"; success=false;;
|
||||
"404" ) echo "Not found"; success=false;;
|
||||
"408" ) echo "Time-out"; success=false;;
|
||||
"451" ) echo "Unavailable For Legal Reasons"; success=false;;
|
||||
"521" ) echo "Web Server Is Down (Cloudflare)"; success=false;;
|
||||
"522" ) echo "Connection Timed Out (Cloudflare)"; success=false;;
|
||||
"500" ) echo "Internal Server Error"; success=false;;
|
||||
* ) echo "Status $err"; success=false;;
|
||||
esac
|
||||
|
||||
# Process result
|
||||
gravity_patternCheck "${patternBuffer}" ${success} "${err}"
|
||||
|
||||
# Delete temp file if it hasn't been moved
|
||||
if [[ -f "${patternBuffer}" ]]; then
|
||||
rm "${patternBuffer}"
|
||||
fi
|
||||
}
|
||||
|
||||
# transport - curl the specified url with any needed command extentions, then patternCheck
|
||||
function gravity_transport() {
|
||||
url=$1
|
||||
cmd_ext=$2
|
||||
agent=$3
|
||||
# tmp file, so we don't have to store the (long!) lists in RAM
|
||||
patternBuffer=$(mktemp)
|
||||
heisenbergCompensator=""
|
||||
if [[ -r $saveLocation ]]; then
|
||||
# if domain has been saved, add file for date check to only download newer
|
||||
heisenbergCompensator="-z $saveLocation"
|
||||
fi
|
||||
# Silently curl url
|
||||
curl -s $cmd_ext $heisenbergCompensator -A "$agent" $url > $patternBuffer
|
||||
|
||||
gravity_patternCheck $patternBuffer
|
||||
|
||||
# Cleanup
|
||||
rm -f $patternBuffer
|
||||
|
||||
}
|
||||
# spinup - main gravity function
|
||||
function gravity_spinup() {
|
||||
gravity_spinup() {
|
||||
echo ":::"
|
||||
# Loop through domain list. Download each one and remove commented lines (lines beginning with '# 'or '/') and # blank lines
|
||||
for ((i = 0; i < "${#sources[@]}"; i++)); do
|
||||
url=${sources[$i]}
|
||||
# Get just the domain from the URL
|
||||
domain=$(echo "${url}" | cut -d'/' -f3)
|
||||
|
||||
# Loop through domain list. Download each one and remove commented lines (lines beginning with '# 'or '/') and blank lines
|
||||
for ((i = 0; i < "${#sources[@]}"; i++))
|
||||
do
|
||||
url=${sources[$i]}
|
||||
# Get just the domain from the URL
|
||||
domain=$(echo "$url" | cut -d'/' -f3)
|
||||
# Save the file as list.#.domain
|
||||
saveLocation=${piholeDir}/list.${i}.${domain}.${justDomainsExtension}
|
||||
activeDomains[$i]=${saveLocation}
|
||||
|
||||
# Save the file as list.#.domain
|
||||
saveLocation=$piholeDir/list.$i.$domain.$justDomainsExtension
|
||||
activeDomains[$i]=$saveLocation
|
||||
agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36"
|
||||
|
||||
agent="Mozilla/10.0"
|
||||
# Use a case statement to download lists that need special cURL commands
|
||||
# to complete properly and reset the user agent when required
|
||||
case "${domain}" in
|
||||
"adblock.mahakala.is")
|
||||
agent='Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36'
|
||||
cmd_ext="-e http://forum.xda-developers.com/"
|
||||
;;
|
||||
|
||||
echo -n "Getting $domain list... "
|
||||
"adaway.org")
|
||||
agent='Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36'
|
||||
;;
|
||||
|
||||
# Use a case statement to download lists that need special cURL commands
|
||||
# to complete properly and reset the user agent when required
|
||||
case "$domain" in
|
||||
"adblock.mahakala.is")
|
||||
agent='Mozilla/5.0 (X11; Linux x86_64; rv:30.0) Gecko/20100101 Firefox/30.0'
|
||||
cmd_ext="-e http://forum.xda-developers.com/"
|
||||
;;
|
||||
"pgl.yoyo.org")
|
||||
cmd_ext="-d mimetype=plaintext -d hostformat=hosts"
|
||||
;;
|
||||
|
||||
"pgl.yoyo.org")
|
||||
cmd_ext="-d mimetype=plaintext -d hostformat=hosts"
|
||||
;;
|
||||
|
||||
# Default is a simple request
|
||||
*) cmd_ext=""
|
||||
# Default is a simple request
|
||||
*) cmd_ext=""
|
||||
esac
|
||||
gravity_transport $url $cmd_ext $agent
|
||||
done
|
||||
if [[ "${skipDownload}" == false ]]; then
|
||||
echo -n "::: Getting $domain list..."
|
||||
gravity_transport "$url" "$cmd_ext" "$agent"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Schwarzchild - aggregate domains to one list and add blacklisted domains
|
||||
function gravity_Schwarzchild() {
|
||||
gravity_Schwarzchild() {
|
||||
echo "::: "
|
||||
# Find all active domains and compile them into one file and remove CRs
|
||||
echo -n "::: Aggregating list of domains..."
|
||||
truncate -s 0 ${piholeDir}/${matterAndLight}
|
||||
for i in "${activeDomains[@]}"; do
|
||||
# Only assimilate list if it is available (download might have faild permanently)
|
||||
if [[ -r "${i}" ]]; then
|
||||
cat "${i}" | tr -d '\r' >> ${piholeDir}/${matterAndLight}
|
||||
fi
|
||||
done
|
||||
echo " done!"
|
||||
}
|
||||
|
||||
# Find all active domains and compile them into one file and remove CRs
|
||||
echo "** Aggregating list of domains..."
|
||||
truncate -s 0 $piholeDir/$matter
|
||||
for i in "${activeDomains[@]}"
|
||||
do
|
||||
cat $i |tr -d '\r' >> $piholeDir/$matter
|
||||
gravity_Blacklist() {
|
||||
# Append blacklist entries to eventHorizon if they exist
|
||||
if [[ -f "${blacklistFile}" ]]; then
|
||||
numBlacklisted=$(wc -l < "${blacklistFile}")
|
||||
plural=; [[ "$numBlacklisted" != "1" ]] && plural=s
|
||||
echo "::: Exact blocked domain${plural}: $numBlacklisted"
|
||||
else
|
||||
echo "::: Nothing to blacklist!"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
gravity_Wildcard() {
|
||||
# Return number of wildcards in output - don't actually handle wildcards
|
||||
if [[ -f "${wildcardlist}" ]]; then
|
||||
numWildcards=$(grep -c ^ "${wildcardlist}")
|
||||
if [[ -n "${IPV4_ADDRESS}" && -n "${IPV6_ADDRESS}" ]];then
|
||||
let numWildcards/=2
|
||||
fi
|
||||
plural=; [[ "$numWildcards" != "1" ]] && plural=s
|
||||
echo "::: Wildcard blocked domain${plural}: $numWildcards"
|
||||
else
|
||||
echo "::: No wildcards used!"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
gravity_Whitelist() {
|
||||
#${piholeDir}/${eventHorizon})
|
||||
echo ":::"
|
||||
# Prevent our sources from being pulled into the hole
|
||||
plural=; [[ "${sources[@]}" != "1" ]] && plural=s
|
||||
echo -n "::: Adding adlist source${plural} to the whitelist..."
|
||||
|
||||
urls=()
|
||||
for url in "${sources[@]}"; do
|
||||
tmp=$(echo "${url}" | awk -F '/' '{print $3}')
|
||||
urls=("${urls[@]}" ${tmp})
|
||||
done
|
||||
echo " done!"
|
||||
|
||||
# Ensure adlist domains are in whitelist.txt
|
||||
${whitelistScript} -nr -q "${urls[@]}" > /dev/null
|
||||
|
||||
# Check whitelist.txt exists.
|
||||
if [[ -f "${whitelistFile}" ]]; then
|
||||
# Remove anything in whitelist.txt from the Event Horizon
|
||||
numWhitelisted=$(wc -l < "${whitelistFile}")
|
||||
plural=; [[ "$numWhitelisted" != "1" ]] && plural=s
|
||||
echo -n "::: Whitelisting $numWhitelisted domain${plural}..."
|
||||
#print everything from preEventHorizon into eventHorizon EXCEPT domains in whitelist.txt
|
||||
grep -F -x -v -f ${whitelistFile} ${piholeDir}/${preEventHorizon} > ${piholeDir}/${eventHorizon}
|
||||
echo " done!"
|
||||
else
|
||||
echo "::: Nothing to whitelist!"
|
||||
fi
|
||||
}
|
||||
|
||||
gravity_unique() {
|
||||
# Sort and remove duplicates
|
||||
echo -n "::: Removing duplicate domains...."
|
||||
sort -u ${piholeDir}/${supernova} > ${piholeDir}/${preEventHorizon}
|
||||
echo " done!"
|
||||
numberOf=$(wc -l < ${piholeDir}/${preEventHorizon})
|
||||
echo "::: $numberOf unique domains trapped in the event horizon."
|
||||
}
|
||||
|
||||
gravity_doHostFormat() {
|
||||
# Check vars from setupVars.conf to see if we're using IPv4, IPv6, Or both.
|
||||
if [[ -n "${IPV4_ADDRESS}" && -n "${IPV6_ADDRESS}" ]];then
|
||||
# Both IPv4 and IPv6
|
||||
awk -v ipv4addr="$IPV4_ADDRESS" -v ipv6addr="$IPV6_ADDRESS" '{sub(/\r$/,""); print ipv4addr" "$0"\n"ipv6addr" "$0}' >> "${2}" < "${1}"
|
||||
elif [[ -n "${IPV4_ADDRESS}" && -z "${IPV6_ADDRESS}" ]];then
|
||||
# Only IPv4
|
||||
awk -v ipv4addr="$IPV4_ADDRESS" '{sub(/\r$/,""); print ipv4addr" "$0}' >> "${2}" < "${1}"
|
||||
elif [[ -z "${IPV4_ADDRESS}" && -n "${IPV6_ADDRESS}" ]];then
|
||||
# Only IPv6
|
||||
awk -v ipv6addr="$IPV6_ADDRESS" '{sub(/\r$/,""); print ipv6addr" "$0}' >> "${2}" < "${1}"
|
||||
elif [[ -z "${IPV4_ADDRESS}" && -z "${IPV6_ADDRESS}" ]];then
|
||||
echo "::: No IP Values found! Please run 'pihole -r' and choose reconfigure to restore values"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
gravity_hostFormatLocal() {
|
||||
# Format domain list as "192.168.x.x domain.com"
|
||||
|
||||
if [[ -f /etc/hostname ]]; then
|
||||
hostname=$(</etc/hostname)
|
||||
elif [ -x "$(command -v hostname)" ]; then
|
||||
hostname=$(hostname -f)
|
||||
else
|
||||
echo "::: Error: Unable to determine fully qualified domain name of host"
|
||||
fi
|
||||
|
||||
echo -e "${hostname}\npi.hole" > "${localList}.tmp"
|
||||
# Copy the file over as /etc/pihole/local.list so dnsmasq can use it
|
||||
rm "${localList}"
|
||||
gravity_doHostFormat "${localList}.tmp" "${localList}"
|
||||
rm "${localList}.tmp"
|
||||
}
|
||||
|
||||
gravity_hostFormatGravity() {
|
||||
# Format domain list as "192.168.x.x domain.com"
|
||||
echo "" > "${piholeDir}/${accretionDisc}"
|
||||
gravity_doHostFormat "${piholeDir}/${eventHorizon}" "${piholeDir}/${accretionDisc}"
|
||||
# Copy the file over as /etc/pihole/gravity.list so dnsmasq can use it
|
||||
mv "${piholeDir}/${accretionDisc}" "${adList}"
|
||||
}
|
||||
|
||||
gravity_hostFormatBlack() {
|
||||
if [[ -f "${blacklistFile}" ]]; then
|
||||
numBlacklisted=$(wc -l < "${blacklistFile}")
|
||||
# Format domain list as "192.168.x.x domain.com"
|
||||
gravity_doHostFormat "${blacklistFile}" "${blackList}.tmp"
|
||||
# Copy the file over as /etc/pihole/black.list so dnsmasq can use it
|
||||
mv "${blackList}.tmp" "${blackList}"
|
||||
else
|
||||
echo "::: Nothing to blacklist!"
|
||||
fi
|
||||
}
|
||||
|
||||
# blackbody - remove any remnant files from script processes
|
||||
gravity_blackbody() {
|
||||
# Loop through list files
|
||||
for file in ${piholeDir}/*.${justDomainsExtension}; do
|
||||
# If list is in active array then leave it (noop) else rm the list
|
||||
if [[ " ${activeDomains[@]} " =~ ${file} ]]; then
|
||||
:
|
||||
else
|
||||
rm -f "${file}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
gravity_advanced() {
|
||||
# Remove comments and print only the domain name
|
||||
# Most of the lists downloaded are already in hosts file format but the spacing/formating is not contigious
|
||||
# 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
|
||||
echo -n "::: Formatting list of domains to remove comments...."
|
||||
#awk '($1 !~ /^#/) { if (NF>1) {print $2} else {print $1}}' ${piholeDir}/${matterAndLight} | sed -nr -e 's/\.{2,}/./g' -e '/\./p' > ${piholeDir}/${supernova}
|
||||
#Above line does not correctly grab domains where comment is on the same line (e.g 'addomain.com #comment')
|
||||
#Awk -F splits on given IFS, we grab the right hand side (chops trailing #coments and /'s to grab the domain only.
|
||||
#Last awk command takes non-commented lines and if they have 2 fields, take the left field (the domain) and leave
|
||||
#+ the right (IP address), otherwise grab the single field.
|
||||
cat ${piholeDir}/${matterAndLight} | \
|
||||
awk -F '#' '{print $1}' | \
|
||||
awk -F '/' '{print $1}' | \
|
||||
awk '($1 !~ /^#/) { if (NF>1) {print $2} else {print $1}}' | \
|
||||
sed -nr -e 's/\.{2,}/./g' -e '/\./p' > ${piholeDir}/${supernova}
|
||||
echo " done!"
|
||||
|
||||
numberOf=$(wc -l < ${piholeDir}/${supernova})
|
||||
echo "::: ${numberOf} domains being pulled in by gravity..."
|
||||
|
||||
gravity_unique
|
||||
}
|
||||
|
||||
gravity_reload() {
|
||||
|
||||
# Reload hosts file
|
||||
echo ":::"
|
||||
echo -n "::: Refresh lists in dnsmasq..."
|
||||
|
||||
#ensure /etc/dnsmasq.d/01-pihole.conf is pointing at the correct list!
|
||||
#First escape forward slashes in the path:
|
||||
adList=${adList//\//\\\/}
|
||||
#Now replace the line in dnsmasq file
|
||||
# sed -i "s/^addn-hosts.*/addn-hosts=$adList/" /etc/dnsmasq.d/01-pihole.conf
|
||||
|
||||
"${PIHOLE_COMMAND}" restartdns
|
||||
echo " done!"
|
||||
}
|
||||
|
||||
for var in "$@"; do
|
||||
case "${var}" in
|
||||
"-f" | "--force" ) forceGrav=true;;
|
||||
"-h" | "--help" ) helpFunc;;
|
||||
"-sd" | "--skip-download" ) skipDownload=true;;
|
||||
"-b" | "--blacklist-only" ) blackListOnly=true;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Append blacklist entries if they exist
|
||||
if [[ -r $blacklist ]];then
|
||||
numberOf=$(cat $blacklist | sed '/^\s*$/d' | wc -l)
|
||||
echo "** Blacklisting $numberOf domain(s)..."
|
||||
cat $blacklist >> $piholeDir/$matter
|
||||
fi
|
||||
}
|
||||
|
||||
function gravity_pulsar() {
|
||||
|
||||
# Whitelist (if applicable) domains
|
||||
if [[ -r $whitelist ]];then
|
||||
# Remove whitelist entries
|
||||
numberOf=$(cat $whitelist | sed '/^\s*$/d' | wc -l)
|
||||
plural=; [[ "$numberOf" != "1" ]] && plural=s
|
||||
echo "** Whitelisting $numberOf domain${plural}..."
|
||||
|
||||
# Append a "$" to the end, prepend a "^" to the beginning, and
|
||||
# replace "." with "\." of each line to turn each entry into a
|
||||
# regexp so it can be parsed out with grep -x
|
||||
awk -F '[# \t]' 'NF>0&&$1!="" {print "^"$1"$"}' $whitelist | sed 's/\./\\./g' > $latentWhitelist
|
||||
else
|
||||
rm $latentWhitelist
|
||||
if [[ "${forceGrav}" == true ]]; then
|
||||
echo -n "::: Deleting exising list cache..."
|
||||
rm /etc/pihole/list.*
|
||||
echo " done!"
|
||||
fi
|
||||
|
||||
# Prevent our sources from being pulled into the hole
|
||||
plural=; [[ "${#sources[@]}" != "1" ]] && plural=s
|
||||
echo "** Whitelisting ${#sources[@]} ad list source${plural}..."
|
||||
for url in ${sources[@]}
|
||||
do
|
||||
echo "$url" | awk -F '/' '{print "^"$3"$"}' | sed 's/\./\\./g' >> $latentWhitelist
|
||||
done
|
||||
if [[ ! "${blackListOnly}" == true ]]; then
|
||||
gravity_collapse
|
||||
gravity_spinup
|
||||
if [[ "${skipDownload}" == false ]]; then
|
||||
gravity_Schwarzchild
|
||||
gravity_advanced
|
||||
else
|
||||
echo "::: Using cached Event Horizon list..."
|
||||
numberOf=$(wc -l < ${piholeDir}/${preEventHorizon})
|
||||
echo "::: $numberOf unique domains trapped in the event horizon."
|
||||
fi
|
||||
gravity_Whitelist
|
||||
fi
|
||||
gravity_Blacklist
|
||||
gravity_Wildcard
|
||||
|
||||
# Remove whitelist entries from list
|
||||
grep -vxf $latentWhitelist $piholeDir/$matter > $piholeDir/$andLight
|
||||
}
|
||||
echo -n "::: Formatting domains into a HOSTS file..."
|
||||
if [[ ! "${blackListOnly}" == true ]]; then
|
||||
gravity_hostFormatLocal
|
||||
gravity_hostFormatGravity
|
||||
fi
|
||||
gravity_hostFormatBlack
|
||||
echo " done!"
|
||||
|
||||
function gravity_unique() {
|
||||
# Sort and remove duplicates
|
||||
sort -u $piholeDir/$supernova > $piholeDir/$eventHorizon
|
||||
numberOf=$(wc -l < $piholeDir/$eventHorizon)
|
||||
echo "** $numberOf unique domains trapped in the event horizon."
|
||||
}
|
||||
function gravity_hostFormat() {
|
||||
# Format domain list as "192.168.x.x domain.com"
|
||||
echo "** Formatting domains into a HOSTS file..."
|
||||
cat $piholeDir/$eventHorizon | awk '{sub(/\r$/,""); print "'"$piholeIP"' " $0}' > $piholeDir/$accretionDisc
|
||||
# Copy the file over as /etc/pihole/gravity.list so dnsmasq can use it
|
||||
cp $piholeDir/$accretionDisc $adList
|
||||
}
|
||||
function gravity_blackbody() {
|
||||
for file in $piholeDir/*.$justDomainsExtension
|
||||
do
|
||||
if [[ " ${activeDomains[@]} " =~ " ${file} " ]]; then
|
||||
:
|
||||
else
|
||||
rm -f $file
|
||||
fi
|
||||
done
|
||||
}
|
||||
function gravity_advanced() {
|
||||
|
||||
# Remove comments and print only the domain name
|
||||
# Most of the lists downloaded are already in hosts file format but the spacing/formating is not contigious
|
||||
# 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
|
||||
awk '($1 !~ /^#/) { if (NF>1) {print $2} else {print $1}}' $piholeDir/$andLight | \
|
||||
sed -nr -e 's/\.{2,}/./g' -e '/\./p' > $piholeDir/$supernova
|
||||
|
||||
numberOf=$(wc -l < $piholeDir/$supernova)
|
||||
echo "** $numberOf domains being pulled in by gravity..."
|
||||
gravity_unique
|
||||
|
||||
sudo kill -HUP $(pidof dnsmasq)
|
||||
}
|
||||
|
||||
gravity_collapse
|
||||
gravity_spinup
|
||||
gravity_Schwarzchild
|
||||
gravity_pulsar
|
||||
gravity_hostFormat
|
||||
gravity_advanced
|
||||
gravity_blackbody
|
||||
|
||||
if [[ ! "${blackListOnly}" == true ]]; then
|
||||
#Clear no longer needed files...
|
||||
echo ":::"
|
||||
echo -n "::: Cleaning up un-needed files..."
|
||||
rm ${piholeDir}/pihole.*.txt
|
||||
echo " done!"
|
||||
fi
|
||||
|
||||
gravity_reload
|
||||
"${PIHOLE_COMMAND}" status
|
||||
|
429
pihole
Executable file
429
pihole
Executable file
@@ -0,0 +1,429 @@
|
||||
#!/bin/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.
|
||||
#
|
||||
# Controller for all pihole scripts and functions.
|
||||
#
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
readonly PI_HOLE_SCRIPT_DIR="/opt/pihole"
|
||||
readonly wildcardlist="/etc/dnsmasq.d/03-pihole-wildcard.conf"
|
||||
|
||||
# Must be root to use this tool
|
||||
if [[ ! $EUID -eq 0 ]];then
|
||||
if [[ -x "$(command -v sudo)" ]]; then
|
||||
exec sudo bash "$0" "$@"
|
||||
exit $?
|
||||
else
|
||||
echo "::: sudo is needed to run pihole commands. Please run this script as root or install sudo."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
webpageFunc() {
|
||||
source /opt/pihole/webpage.sh
|
||||
main "$@"
|
||||
exit 0
|
||||
}
|
||||
|
||||
whitelistFunc() {
|
||||
"${PI_HOLE_SCRIPT_DIR}"/list.sh "$@"
|
||||
exit 0
|
||||
}
|
||||
|
||||
blacklistFunc() {
|
||||
"${PI_HOLE_SCRIPT_DIR}"/list.sh "$@"
|
||||
exit 0
|
||||
}
|
||||
|
||||
wildcardFunc() {
|
||||
"${PI_HOLE_SCRIPT_DIR}"/list.sh "$@"
|
||||
exit 0
|
||||
}
|
||||
|
||||
debugFunc() {
|
||||
local automated
|
||||
local web
|
||||
|
||||
# Pull off the `debug` leaving passed call augmentation flags in $1
|
||||
shift
|
||||
if [[ "$@" == *"-a"* ]]; then
|
||||
automated="true"
|
||||
fi
|
||||
if [[ "$@" == *"-w"* ]]; then
|
||||
web="true"
|
||||
fi
|
||||
|
||||
AUTOMATED=${automated:-} WEBCALL=${web:-} "${PI_HOLE_SCRIPT_DIR}"/piholeDebug.sh
|
||||
exit 0
|
||||
}
|
||||
|
||||
flushFunc() {
|
||||
"${PI_HOLE_SCRIPT_DIR}"/piholeLogFlush.sh "$@"
|
||||
exit 0
|
||||
}
|
||||
|
||||
updatePiholeFunc() {
|
||||
"${PI_HOLE_SCRIPT_DIR}"/update.sh
|
||||
exit 0
|
||||
}
|
||||
|
||||
reconfigurePiholeFunc() {
|
||||
/etc/.pihole/automated\ install/basic-install.sh --reconfigure
|
||||
exit 0;
|
||||
}
|
||||
|
||||
updateGravityFunc() {
|
||||
"${PI_HOLE_SCRIPT_DIR}"/gravity.sh "$@"
|
||||
exit 0
|
||||
}
|
||||
|
||||
scanList(){
|
||||
domain="${1}"
|
||||
list="${2}"
|
||||
method="${3}"
|
||||
if [[ ${method} == "-exact" ]] ; then
|
||||
grep -i -E "(^|\s)${domain}($|\s)" "${list}"
|
||||
else
|
||||
grep -i "${domain}" "${list}"
|
||||
fi
|
||||
}
|
||||
|
||||
processWildcards() {
|
||||
IFS="." read -r -a array <<< "${1}"
|
||||
for (( i=${#array[@]}-1; i>=0; i-- )); do
|
||||
ar=""
|
||||
for (( j=${#array[@]}-1; j>${#array[@]}-i-2; j-- )); do
|
||||
if [[ $j == $((${#array[@]}-1)) ]]; then
|
||||
ar="${array[$j]}"
|
||||
else
|
||||
ar="${array[$j]}.${ar}"
|
||||
fi
|
||||
done
|
||||
echo "${ar}"
|
||||
done
|
||||
}
|
||||
|
||||
queryFunc() {
|
||||
domain="${2}"
|
||||
method="${3}"
|
||||
lists=( /etc/pihole/list.* /etc/pihole/blacklist.txt)
|
||||
for list in ${lists[@]}; do
|
||||
if [ -e "${list}" ]; then
|
||||
result=$(scanList ${domain} ${list} ${method})
|
||||
# Remove empty lines before couting number of results
|
||||
count=$(sed '/^\s*$/d' <<< "$result" | wc -l)
|
||||
echo "::: ${list} (${count} results)"
|
||||
if [[ ${count} > 0 ]]; then
|
||||
echo "${result}"
|
||||
fi
|
||||
echo ""
|
||||
else
|
||||
echo "::: ${list} does not exist"
|
||||
echo ""
|
||||
fi
|
||||
done
|
||||
|
||||
# Scan for possible wildcard matches
|
||||
if [ -e "${wildcardlist}" ]; then
|
||||
local wildcards=($(processWildcards "${domain}"))
|
||||
for domain in ${wildcards[@]}; do
|
||||
result=$(scanList "\/${domain}\/" ${wildcardlist})
|
||||
# Remove empty lines before couting number of results
|
||||
count=$(sed '/^\s*$/d' <<< "$result" | wc -l)
|
||||
if [[ ${count} > 0 ]]; then
|
||||
echo "::: Wildcard blocking ${domain} (${count} results)"
|
||||
echo "${result}"
|
||||
echo ""
|
||||
fi
|
||||
done
|
||||
fi
|
||||
exit 0
|
||||
}
|
||||
|
||||
chronometerFunc() {
|
||||
shift
|
||||
"${PI_HOLE_SCRIPT_DIR}"/chronometer.sh "$@"
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
||||
uninstallFunc() {
|
||||
"${PI_HOLE_SCRIPT_DIR}"/uninstall.sh
|
||||
exit 0
|
||||
}
|
||||
|
||||
versionFunc() {
|
||||
shift
|
||||
"${PI_HOLE_SCRIPT_DIR}"/version.sh "$@"
|
||||
exit 0
|
||||
}
|
||||
|
||||
restartDNS() {
|
||||
dnsmasqPid=$(pidof dnsmasq)
|
||||
if [[ "${dnsmasqPid}" ]]; then
|
||||
# Service already running - reload config
|
||||
if [[ -x "$(command -v systemctl)" ]]; then
|
||||
systemctl restart dnsmasq
|
||||
else
|
||||
service dnsmasq restart
|
||||
fi
|
||||
else
|
||||
# Service not running, start it up
|
||||
if [[ -x "$(command -v systemctl)" ]]; then
|
||||
systemctl start dnsmasq
|
||||
else
|
||||
service dnsmasq start
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
piholeEnable() {
|
||||
if [[ "${2}" == "-h" ]] || [[ "${2}" == "--help" ]]; then
|
||||
echo "Usage: pihole disable [time]
|
||||
Example: 'pihole disable', or 'pihole disable 5m'
|
||||
Disable Pi-hole subsystems
|
||||
|
||||
Time:
|
||||
#s Disable Pi-hole functionality for # second(s)
|
||||
#m Disable Pi-hole functionality for # minute(s)"
|
||||
exit 0
|
||||
elif [[ "${1}" == "0" ]]; then
|
||||
# Disable Pi-hole
|
||||
sed -i 's/^addn-hosts=\/etc\/pihole\/gravity.list/#addn-hosts=\/etc\/pihole\/gravity.list/' /etc/dnsmasq.d/01-pihole.conf
|
||||
sed -i 's/^addn-hosts=\/etc\/pihole\/black.list/#addn-hosts=\/etc\/pihole\/black.list/' /etc/dnsmasq.d/01-pihole.conf
|
||||
if [[ -e "$wildcardlist" ]]; then
|
||||
mv "$wildcardlist" "/etc/pihole/wildcard.list"
|
||||
fi
|
||||
echo "::: Blocking has been disabled!"
|
||||
if [[ $# > 1 ]]; then
|
||||
if [[ "${2}" == *"s"* ]]; then
|
||||
tt=${2%"s"}
|
||||
echo "::: Blocking will be re-enabled in ${tt} seconds"
|
||||
nohup bash -c "sleep ${tt}; pihole enable" </dev/null &>/dev/null &
|
||||
elif [[ "${2}" == *"m"* ]]; then
|
||||
tt=${2%"m"}
|
||||
echo "::: Blocking will be re-enabled in ${tt} minutes"
|
||||
tt=$((${tt}*60))
|
||||
nohup bash -c "sleep ${tt}; pihole enable" </dev/null &>/dev/null &
|
||||
else
|
||||
echo "::: Unknown format for delayed reactivation of the blocking!"
|
||||
echo "::: Example:"
|
||||
echo "::: pihole disable 5s - will disable blocking for 5 seconds"
|
||||
echo "::: pihole disable 7m - will disable blocking for 7 minutes"
|
||||
echo "::: Blocking will not automatically be re-enabled!"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# Enable Pi-hole
|
||||
echo "::: Blocking has been enabled!"
|
||||
sed -i 's/^#addn-hosts/addn-hosts/' /etc/dnsmasq.d/01-pihole.conf
|
||||
if [[ -e "/etc/pihole/wildcard.list" ]]; then
|
||||
mv "/etc/pihole/wildcard.list" "$wildcardlist"
|
||||
fi
|
||||
fi
|
||||
restartDNS
|
||||
}
|
||||
|
||||
piholeLogging() {
|
||||
shift
|
||||
if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]]; then
|
||||
echo "Usage: pihole logging [options]
|
||||
Example: 'pihole logging on'
|
||||
Specify whether the Pi-hole log should be used
|
||||
|
||||
Options:
|
||||
on Enable the Pi-hole log at /var/log/pihole.log
|
||||
off Disable the Pi-hole log at /var/log/pihole.log"
|
||||
exit 0
|
||||
elif [[ "${1}" == "off" ]]; then
|
||||
# Disable logging
|
||||
sed -i 's/^log-queries/#log-queries/' /etc/dnsmasq.d/01-pihole.conf
|
||||
sed -i 's/^QUERY_LOGGING=true/QUERY_LOGGING=false/' /etc/pihole/setupVars.conf
|
||||
pihole -f
|
||||
echo "::: Logging has been disabled!"
|
||||
elif [[ "${1}" == "on" ]]; then
|
||||
# Enable logging
|
||||
sed -i 's/^#log-queries/log-queries/' /etc/dnsmasq.d/01-pihole.conf
|
||||
sed -i 's/^QUERY_LOGGING=false/QUERY_LOGGING=true/' /etc/pihole/setupVars.conf
|
||||
echo "::: Logging has been enabled!"
|
||||
else
|
||||
echo "::: Invalid option passed, please pass 'on' or 'off'"
|
||||
exit 1
|
||||
fi
|
||||
restartDNS
|
||||
}
|
||||
|
||||
piholeStatus() {
|
||||
if [[ "$(netstat -plnt | grep -c ':53 ')" -gt "0" ]]; then
|
||||
if [[ "${1}" != "web" ]]; then
|
||||
echo "::: DNS service is running"
|
||||
fi
|
||||
else
|
||||
if [[ "${1}" == "web" ]]; then
|
||||
echo "-1";
|
||||
else
|
||||
echo "::: DNS service is NOT running"
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ "$(grep -i "^#addn-hosts=/" /etc/dnsmasq.d/01-pihole.conf)" ]]; then
|
||||
# List is commented out
|
||||
if [[ "${1}" == "web" ]]; then
|
||||
echo 0;
|
||||
else
|
||||
echo "::: Pi-hole blocking is Disabled";
|
||||
fi
|
||||
elif [[ "$(grep -i "^addn-hosts=/" /etc/dnsmasq.d/01-pihole.conf)" ]]; then
|
||||
# List set
|
||||
if [[ "${1}" == "web" ]]; then
|
||||
echo 1;
|
||||
else
|
||||
echo "::: Pi-hole blocking is Enabled";
|
||||
fi
|
||||
else
|
||||
# Addn-host not found
|
||||
if [[ "${1}" == "web" ]]; then
|
||||
echo 99
|
||||
else
|
||||
echo "::: No hosts file linked to dnsmasq, adding it in enabled state"
|
||||
fi
|
||||
# Add addn-host= to dnsmasq
|
||||
echo "addn-hosts=/etc/pihole/gravity.list" >> /etc/dnsmasq.d/01-pihole.conf
|
||||
restartDNS
|
||||
fi
|
||||
}
|
||||
|
||||
tailFunc() {
|
||||
echo "Press Ctrl-C to exit"
|
||||
tail -F /var/log/pihole.log
|
||||
exit 0
|
||||
}
|
||||
|
||||
piholeCheckoutFunc() {
|
||||
if [[ "$2" == "-h" ]] || [[ "$2" == "--help" ]]; then
|
||||
echo "Usage: pihole checkout [repo] [branch]
|
||||
Example: 'pihole checkout master' or 'pihole checkout core dev'
|
||||
Switch Pi-hole subsystems to a different Github branch
|
||||
|
||||
Repositories:
|
||||
core [branch] Change the branch of Pi-hole's core subsystem
|
||||
web [branch] Change the branch of Admin Console subsystem
|
||||
|
||||
Branches:
|
||||
master Update subsystems to the latest stable release
|
||||
dev Update subsystems to the latest development release"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
source "${PI_HOLE_SCRIPT_DIR}"/piholeCheckout.sh
|
||||
shift
|
||||
checkout "$@"
|
||||
}
|
||||
|
||||
tricorderFunc() {
|
||||
if [[ ! -p "/dev/stdin" ]]; then
|
||||
echo "Please do not call Tricorder directly."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! timeout 2 nc -z tricorder.pi-hole.net 9998 &> /dev/null; then
|
||||
echo "Unable to connect to Pi-hole's Tricorder server."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if command -v openssl &> /dev/null; then
|
||||
openssl s_client -quiet -connect tricorder.pi-hole.net:9998 2> /dev/null < /dev/stdin
|
||||
exit "$?"
|
||||
else
|
||||
echo "Your debug log will be transmitted unencrypted via plain-text"
|
||||
echo "There is a possibility that this could be intercepted by a third party"
|
||||
echo "If you wish to cancel, press Ctrl-C to exit within 10 seconds"
|
||||
secs="10"
|
||||
while [[ "$secs" -gt "0" ]]; do
|
||||
echo -ne "."
|
||||
sleep 1
|
||||
: $((secs--))
|
||||
done
|
||||
echo " "
|
||||
nc tricorder.pi-hole.net 9999 < /dev/stdin
|
||||
exit "$?"
|
||||
fi
|
||||
}
|
||||
|
||||
helpFunc() {
|
||||
echo "Usage: pihole [options]
|
||||
Example: 'pihole -w -h'
|
||||
Add '-h' after specific commands for more information on usage
|
||||
|
||||
Whitelist/Blacklist Options:
|
||||
-w, whitelist Whitelist domain(s)
|
||||
-b, blacklist Blacklist domain(s)
|
||||
-wild, wildcard Blacklist domain(s), and all its subdomains
|
||||
Add '-h' for more info on whitelist/blacklist usage
|
||||
|
||||
Debugging Options:
|
||||
-d, debug Start a debugging session
|
||||
Add '-a' to enable automated debugging
|
||||
-f, flush Flush the Pi-hole log
|
||||
-r, reconfigure Reconfigure or Repair Pi-hole subsystems
|
||||
-t, tail View the live output of the Pi-hole log
|
||||
|
||||
Options:
|
||||
-a, admin Admin Console options
|
||||
Add '-h' for more info on admin console usage
|
||||
-c, chronometer Calculates stats and displays to an LCD
|
||||
Add '-h' for more info on chronometer usage
|
||||
-g, updateGravity Update the list of ad-serving domains
|
||||
-h, --help, help Show this help dialog
|
||||
-l, logging Specify whether the Pi-hole log should be used
|
||||
Add '-h' for more info on logging usage
|
||||
-q, query Query the adlists for a specified domain
|
||||
Add '-exact' AFTER a specified domain for exact match
|
||||
-up, updatePihole Update Pi-hole subsystems
|
||||
-v, version Show installed versions of Pi-hole, Admin Console & FTL
|
||||
Add '-h' for more info on version usage
|
||||
uninstall Uninstall Pi-hole from your system
|
||||
status Display the running status of Pi-hole subsystems
|
||||
enable Enable Pi-hole subsystems
|
||||
disable Disable Pi-hole subsystems
|
||||
Add '-h' for more info on disable usage
|
||||
restartdns Restart Pi-hole subsystems
|
||||
checkout Switch Pi-hole subsystems to a different Github branch
|
||||
Add '-h' for more info on checkout usage";
|
||||
exit 0
|
||||
}
|
||||
|
||||
if [[ $# = 0 ]]; then
|
||||
helpFunc
|
||||
fi
|
||||
|
||||
# Handle redirecting to specific functions based on arguments
|
||||
case "${1}" in
|
||||
"-w" | "whitelist" ) whitelistFunc "$@";;
|
||||
"-b" | "blacklist" ) blacklistFunc "$@";;
|
||||
"-wild" | "wildcard" ) wildcardFunc "$@";;
|
||||
"-d" | "debug" ) debugFunc "$@";;
|
||||
"-f" | "flush" ) flushFunc "$@";;
|
||||
"-up" | "updatePihole" ) updatePiholeFunc;;
|
||||
"-r" | "reconfigure" ) reconfigurePiholeFunc;;
|
||||
"-g" | "updateGravity" ) updateGravityFunc "$@";;
|
||||
"-c" | "chronometer" ) chronometerFunc "$@";;
|
||||
"-h" | "help" ) helpFunc;;
|
||||
"-v" | "version" ) versionFunc "$@";;
|
||||
"-q" | "query" ) queryFunc "$@";;
|
||||
"-l" | "logging" ) piholeLogging "$@";;
|
||||
"uninstall" ) uninstallFunc;;
|
||||
"enable" ) piholeEnable 1;;
|
||||
"disable" ) piholeEnable 0 "$2";;
|
||||
"status" ) piholeStatus "$2";;
|
||||
"restartdns" ) restartDNS;;
|
||||
"-a" | "admin" ) webpageFunc "$@";;
|
||||
"-t" | "tail" ) tailFunc;;
|
||||
"checkout" ) piholeCheckoutFunc "$@";;
|
||||
"tricorder" ) tricorderFunc;;
|
||||
* ) helpFunc;;
|
||||
esac
|
5
requirements.txt
Normal file
5
requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
docker-compose
|
||||
pytest
|
||||
pytest-xdist
|
||||
pytest-cov
|
||||
testinfra
|
0
test/__init__.py
Normal file
0
test/__init__.py
Normal file
16
test/centos.Dockerfile
Normal file
16
test/centos.Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
||||
FROM centos:7
|
||||
|
||||
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
|
||||
|
||||
RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
61
test/conftest.py
Normal file
61
test/conftest.py
Normal file
@@ -0,0 +1,61 @@
|
||||
import pytest
|
||||
import testinfra
|
||||
|
||||
check_output = testinfra.get_backend(
|
||||
"local://"
|
||||
).get_module("Command").check_output
|
||||
|
||||
@pytest.fixture
|
||||
def Pihole(Docker):
|
||||
''' used to contain some script stubbing, now pretty much an alias.
|
||||
Also provides bash as the default run function shell '''
|
||||
def run_bash(self, command, *args, **kwargs):
|
||||
cmd = self.get_command(command, *args)
|
||||
if self.user is not None:
|
||||
out = self.run_local(
|
||||
"docker exec -u %s %s /bin/bash -c %s",
|
||||
self.user, self.name, cmd)
|
||||
else:
|
||||
out = self.run_local(
|
||||
"docker exec %s /bin/bash -c %s", self.name, cmd)
|
||||
out.command = self.encode(cmd)
|
||||
return out
|
||||
|
||||
funcType = type(Docker.run)
|
||||
Docker.run = funcType(run_bash, Docker, testinfra.backend.docker.DockerBackend)
|
||||
return Docker
|
||||
|
||||
@pytest.fixture
|
||||
def Docker(request, args, image, cmd):
|
||||
''' combine our fixtures into a docker run command and setup finalizer to cleanup '''
|
||||
assert 'docker' in check_output('id'), "Are you in the docker group?"
|
||||
docker_run = "docker run {} {} {}".format(args, image, cmd)
|
||||
docker_id = check_output(docker_run)
|
||||
|
||||
def teardown():
|
||||
check_output("docker rm -f %s", docker_id)
|
||||
request.addfinalizer(teardown)
|
||||
|
||||
docker_container = testinfra.get_backend("docker://" + docker_id)
|
||||
docker_container.id = docker_id
|
||||
return docker_container
|
||||
|
||||
@pytest.fixture
|
||||
def args(request):
|
||||
''' -t became required when tput began being used '''
|
||||
return '-t -d'
|
||||
|
||||
@pytest.fixture(params=['debian', 'centos'])
|
||||
def tag(request):
|
||||
''' consumed by image to make the test matrix '''
|
||||
return request.param
|
||||
|
||||
@pytest.fixture()
|
||||
def image(request, tag):
|
||||
''' built by test_000_build_containers.py '''
|
||||
return 'pytest_pihole:{}'.format(tag)
|
||||
|
||||
@pytest.fixture()
|
||||
def cmd(request):
|
||||
''' default to doing nothing by tailing null, but don't exit '''
|
||||
return 'tail -f /dev/null'
|
16
test/debian.Dockerfile
Normal file
16
test/debian.Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
||||
FROM buildpack-deps:jessie-scm
|
||||
|
||||
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
|
||||
|
||||
RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
18
test/test_000_build_containers.py
Normal file
18
test/test_000_build_containers.py
Normal file
@@ -0,0 +1,18 @@
|
||||
''' This file starts with 000 to make it run first '''
|
||||
import pytest
|
||||
import testinfra
|
||||
|
||||
run_local = testinfra.get_backend(
|
||||
"local://"
|
||||
).get_module("Command").run
|
||||
|
||||
@pytest.mark.parametrize("image,tag", [
|
||||
( 'test/debian.Dockerfile', 'pytest_pihole:debian' ),
|
||||
( 'test/centos.Dockerfile', 'pytest_pihole:centos' ),
|
||||
])
|
||||
def test_build_pihole_image(image, tag):
|
||||
build_cmd = run_local('docker build -f {} -t {} .'.format(image, tag))
|
||||
if build_cmd.rc != 0:
|
||||
print build_cmd.stdout
|
||||
print build_cmd.stderr
|
||||
assert build_cmd.rc == 0
|
506
test/test_automated_install.py
Normal file
506
test/test_automated_install.py
Normal file
@@ -0,0 +1,506 @@
|
||||
import pytest
|
||||
from textwrap import dedent
|
||||
|
||||
SETUPVARS = {
|
||||
'PIHOLE_INTERFACE' : 'eth99',
|
||||
'IPV4_ADDRESS' : '1.1.1.1',
|
||||
'IPV6_ADDRESS' : 'FE80::240:D0FF:FE48:4672',
|
||||
'PIHOLE_DNS_1' : '4.2.2.1',
|
||||
'PIHOLE_DNS_2' : '4.2.2.2'
|
||||
}
|
||||
|
||||
def test_setupVars_are_sourced_to_global_scope(Pihole):
|
||||
''' currently update_dialogs sources setupVars with a dot,
|
||||
then various other functions use the variables.
|
||||
This confirms the sourced variables are in scope between functions '''
|
||||
setup_var_file = 'cat <<EOF> /etc/pihole/setupVars.conf\n'
|
||||
for k,v in SETUPVARS.iteritems():
|
||||
setup_var_file += "{}={}\n".format(k, v)
|
||||
setup_var_file += "EOF\n"
|
||||
Pihole.run(setup_var_file)
|
||||
|
||||
script = dedent('''\
|
||||
set -e
|
||||
printSetupVars() {
|
||||
# Currently debug test function only
|
||||
echo "Outputting sourced variables"
|
||||
echo "PIHOLE_INTERFACE=${PIHOLE_INTERFACE}"
|
||||
echo "IPV4_ADDRESS=${IPV4_ADDRESS}"
|
||||
echo "IPV6_ADDRESS=${IPV6_ADDRESS}"
|
||||
echo "PIHOLE_DNS_1=${PIHOLE_DNS_1}"
|
||||
echo "PIHOLE_DNS_2=${PIHOLE_DNS_2}"
|
||||
}
|
||||
update_dialogs() {
|
||||
. /etc/pihole/setupVars.conf
|
||||
}
|
||||
update_dialogs
|
||||
printSetupVars
|
||||
''')
|
||||
|
||||
output = run_script(Pihole, script).stdout
|
||||
|
||||
for k,v in SETUPVARS.iteritems():
|
||||
assert "{}={}".format(k, v) in output
|
||||
|
||||
def test_setupVars_saved_to_file(Pihole):
|
||||
''' confirm saved settings are written to a file for future updates to re-use '''
|
||||
set_setup_vars = '\n' # dedent works better with this and padding matching script below
|
||||
for k,v in SETUPVARS.iteritems():
|
||||
set_setup_vars += " {}={}\n".format(k, v)
|
||||
Pihole.run(set_setup_vars).stdout
|
||||
|
||||
script = dedent('''\
|
||||
set -e
|
||||
echo start
|
||||
TERM=xterm
|
||||
source /opt/pihole/basic-install.sh
|
||||
{}
|
||||
finalExports
|
||||
cat /etc/pihole/setupVars.conf
|
||||
'''.format(set_setup_vars))
|
||||
|
||||
output = run_script(Pihole, script).stdout
|
||||
|
||||
for k,v in SETUPVARS.iteritems():
|
||||
assert "{}={}".format(k, v) in output
|
||||
|
||||
def test_configureFirewall_firewalld_running_no_errors(Pihole):
|
||||
''' confirms firewalld rules are applied when firewallD is running '''
|
||||
# firewallD returns 'running' as status
|
||||
mock_command('firewall-cmd', {'*':('running', 0)}, Pihole)
|
||||
# Whiptail dialog returns Ok for user prompt
|
||||
mock_command('whiptail', {'*':('', 0)}, Pihole)
|
||||
configureFirewall = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
configureFirewall
|
||||
''')
|
||||
expected_stdout = 'Configuring FirewallD for httpd and dnsmasq.'
|
||||
assert expected_stdout in configureFirewall.stdout
|
||||
firewall_calls = Pihole.run('cat /var/log/firewall-cmd').stdout
|
||||
assert 'firewall-cmd --state' in firewall_calls
|
||||
assert 'firewall-cmd --permanent --add-service=http --add-service=dns' in firewall_calls
|
||||
assert 'firewall-cmd --reload' in firewall_calls
|
||||
|
||||
def test_configureFirewall_firewalld_disabled_no_errors(Pihole):
|
||||
''' confirms firewalld rules are not applied when firewallD is not running '''
|
||||
# firewallD returns non-running status
|
||||
mock_command('firewall-cmd', {'*':('not running', '1')}, Pihole)
|
||||
configureFirewall = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
configureFirewall
|
||||
''')
|
||||
expected_stdout = 'No active firewall detected.. skipping firewall configuration.'
|
||||
assert expected_stdout in configureFirewall.stdout
|
||||
|
||||
def test_configureFirewall_firewalld_enabled_declined_no_errors(Pihole):
|
||||
''' confirms firewalld rules are not applied when firewallD is running, user declines ruleset '''
|
||||
# firewallD returns running status
|
||||
mock_command('firewall-cmd', {'*':('running', 0)}, Pihole)
|
||||
# Whiptail dialog returns Cancel for user prompt
|
||||
mock_command('whiptail', {'*':('', 1)}, Pihole)
|
||||
configureFirewall = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
configureFirewall
|
||||
''')
|
||||
expected_stdout = 'Not installing firewall rulesets.'
|
||||
assert expected_stdout in configureFirewall.stdout
|
||||
|
||||
def test_configureFirewall_no_firewall(Pihole):
|
||||
''' confirms firewall skipped no daemon is running '''
|
||||
configureFirewall = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
configureFirewall
|
||||
''')
|
||||
expected_stdout = 'No active firewall detected'
|
||||
assert expected_stdout in configureFirewall.stdout
|
||||
|
||||
def test_configureFirewall_IPTables_enabled_declined_no_errors(Pihole):
|
||||
''' confirms IPTables rules are not applied when IPTables is running, user declines ruleset '''
|
||||
# iptables command exists
|
||||
mock_command('iptables', {'*':('', '0')}, Pihole)
|
||||
# modinfo returns always true (ip_tables module check)
|
||||
mock_command('modinfo', {'*':('', '0')}, Pihole)
|
||||
# Whiptail dialog returns Cancel for user prompt
|
||||
mock_command('whiptail', {'*':('', '1')}, Pihole)
|
||||
configureFirewall = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
configureFirewall
|
||||
''')
|
||||
expected_stdout = 'Not installing firewall rulesets.'
|
||||
assert expected_stdout in configureFirewall.stdout
|
||||
|
||||
def test_configureFirewall_IPTables_enabled_rules_exist_no_errors(Pihole):
|
||||
''' confirms IPTables rules are not applied when IPTables is running and rules exist '''
|
||||
# iptables command exists and returns 0 on calls (should return 0 on iptables -C)
|
||||
mock_command('iptables', {'-S':('-P INPUT DENY', '0')}, Pihole)
|
||||
# modinfo returns always true (ip_tables module check)
|
||||
mock_command('modinfo', {'*':('', '0')}, Pihole)
|
||||
# Whiptail dialog returns Cancel for user prompt
|
||||
mock_command('whiptail', {'*':('', '0')}, Pihole)
|
||||
configureFirewall = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
configureFirewall
|
||||
''')
|
||||
expected_stdout = 'Installing new IPTables firewall rulesets'
|
||||
assert expected_stdout in configureFirewall.stdout
|
||||
firewall_calls = Pihole.run('cat /var/log/iptables').stdout
|
||||
assert 'iptables -I INPUT 1 -p tcp -m tcp --dport 80 -j ACCEPT' not in firewall_calls
|
||||
assert 'iptables -I INPUT 1 -p tcp -m tcp --dport 53 -j ACCEPT' not in firewall_calls
|
||||
assert 'iptables -I INPUT 1 -p udp -m udp --dport 53 -j ACCEPT' not in firewall_calls
|
||||
|
||||
def test_configureFirewall_IPTables_enabled_not_exist_no_errors(Pihole):
|
||||
''' confirms IPTables rules are applied when IPTables is running and rules do not exist '''
|
||||
# iptables command and returns 0 on calls (should return 1 on iptables -C)
|
||||
mock_command('iptables', {'-S':('-P INPUT DENY', '0'), '-C':('', 1), '-I':('', 0)}, Pihole)
|
||||
# modinfo returns always true (ip_tables module check)
|
||||
mock_command('modinfo', {'*':('', '0')}, Pihole)
|
||||
# Whiptail dialog returns Cancel for user prompt
|
||||
mock_command('whiptail', {'*':('', '0')}, Pihole)
|
||||
configureFirewall = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
configureFirewall
|
||||
''')
|
||||
expected_stdout = 'Installing new IPTables firewall rulesets'
|
||||
assert expected_stdout in configureFirewall.stdout
|
||||
firewall_calls = Pihole.run('cat /var/log/iptables').stdout
|
||||
assert 'iptables -I INPUT 1 -p tcp -m tcp --dport 80 -j ACCEPT' in firewall_calls
|
||||
assert 'iptables -I INPUT 1 -p tcp -m tcp --dport 53 -j ACCEPT' in firewall_calls
|
||||
assert 'iptables -I INPUT 1 -p udp -m udp --dport 53 -j ACCEPT' in firewall_calls
|
||||
|
||||
def test_installPiholeWeb_fresh_install_no_errors(Pihole):
|
||||
''' confirms all web page assets from Core repo are installed on a fresh build '''
|
||||
installWeb = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
installPiholeWeb
|
||||
''')
|
||||
assert 'Installing pihole custom index page...' in installWeb.stdout
|
||||
assert 'No default index.lighttpd.html file found... not backing up' in installWeb.stdout
|
||||
web_directory = Pihole.run('ls -r /var/www/html/pihole').stdout
|
||||
assert 'index.php' in web_directory
|
||||
assert 'index.js' in web_directory
|
||||
assert 'blockingpage.css' in web_directory
|
||||
|
||||
def test_installPiholeWeb_empty_directory_no_errors(Pihole):
|
||||
''' confirms all web page assets from Core repo are installed in an emtpy directory '''
|
||||
installWeb = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
mkdir -p /var/www/html/pihole
|
||||
installPiholeWeb
|
||||
''')
|
||||
assert 'Installing pihole custom index page...' in installWeb.stdout
|
||||
assert 'No default index.lighttpd.html file found... not backing up' not in installWeb.stdout
|
||||
assert 'index.php missing, replacing...' in installWeb.stdout
|
||||
assert 'index.js missing, replacing...' in installWeb.stdout
|
||||
assert 'blockingpage.css missing, replacing...' in installWeb.stdout
|
||||
web_directory = Pihole.run('ls -r /var/www/html/pihole').stdout
|
||||
assert 'index.php' in web_directory
|
||||
assert 'index.js' in web_directory
|
||||
assert 'blockingpage.css' in web_directory
|
||||
|
||||
def test_installPiholeWeb_index_php_no_errors(Pihole):
|
||||
''' confirms all web page assets from Core repo are installed when necessary '''
|
||||
installWeb = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
mkdir -p /var/www/html/pihole
|
||||
touch /var/www/html/pihole/index.php
|
||||
installPiholeWeb
|
||||
''')
|
||||
assert 'Installing pihole custom index page...' in installWeb.stdout
|
||||
assert 'No default index.lighttpd.html file found... not backing up' not in installWeb.stdout
|
||||
assert 'Existing index.php detected, not overwriting' in installWeb.stdout
|
||||
assert 'index.js missing, replacing...' in installWeb.stdout
|
||||
assert 'blockingpage.css missing, replacing...' in installWeb.stdout
|
||||
web_directory = Pihole.run('ls -r /var/www/html/pihole').stdout
|
||||
assert 'index.php' in web_directory
|
||||
assert 'index.js' in web_directory
|
||||
assert 'blockingpage.css' in web_directory
|
||||
|
||||
def test_installPiholeWeb_index_js_no_errors(Pihole):
|
||||
''' confirms all web page assets from Core repo are installed when necessary '''
|
||||
installWeb = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
mkdir -p /var/www/html/pihole
|
||||
touch /var/www/html/pihole/index.js
|
||||
installPiholeWeb
|
||||
''')
|
||||
assert 'Installing pihole custom index page...' in installWeb.stdout
|
||||
assert 'No default index.lighttpd.html file found... not backing up' not in installWeb.stdout
|
||||
assert 'index.php missing, replacing...' in installWeb.stdout
|
||||
assert 'Existing index.js detected, not overwriting' in installWeb.stdout
|
||||
assert 'blockingpage.css missing, replacing...' in installWeb.stdout
|
||||
web_directory = Pihole.run('ls -r /var/www/html/pihole').stdout
|
||||
assert 'index.php' in web_directory
|
||||
assert 'index.js' in web_directory
|
||||
assert 'blockingpage.css' in web_directory
|
||||
|
||||
def test_installPiholeWeb_blockingpage_css_no_errors(Pihole):
|
||||
''' confirms all web page assets from Core repo are installed when necessary '''
|
||||
installWeb = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
mkdir -p /var/www/html/pihole
|
||||
touch /var/www/html/pihole/blockingpage.css
|
||||
installPiholeWeb
|
||||
''')
|
||||
assert 'Installing pihole custom index page...' in installWeb.stdout
|
||||
assert 'No default index.lighttpd.html file found... not backing up' not in installWeb.stdout
|
||||
assert 'index.php missing, replacing...' in installWeb.stdout
|
||||
assert 'index.js missing, replacing...' in installWeb.stdout
|
||||
assert 'Existing blockingpage.css detected, not overwriting' in installWeb.stdout
|
||||
web_directory = Pihole.run('ls -r /var/www/html/pihole').stdout
|
||||
assert 'index.php' in web_directory
|
||||
assert 'index.js' in web_directory
|
||||
assert 'blockingpage.css' in web_directory
|
||||
|
||||
def test_installPiholeWeb_already_populated_no_errors(Pihole):
|
||||
''' confirms all web page assets from Core repo are installed when necessary '''
|
||||
installWeb = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
mkdir -p /var/www/html/pihole
|
||||
touch /var/www/html/pihole/index.php
|
||||
touch /var/www/html/pihole/index.js
|
||||
touch /var/www/html/pihole/blockingpage.css
|
||||
installPiholeWeb
|
||||
''')
|
||||
assert 'Installing pihole custom index page...' in installWeb.stdout
|
||||
assert 'No default index.lighttpd.html file found... not backing up' not in installWeb.stdout
|
||||
assert 'Existing index.php detected, not overwriting' in installWeb.stdout
|
||||
assert 'index.php missing, replacing...' not in installWeb.stdout
|
||||
assert 'Existing index.js detected, not overwriting' in installWeb.stdout
|
||||
assert 'index.js missing, replacing...' not in installWeb.stdout
|
||||
assert 'Existing blockingpage.css detected, not overwriting' in installWeb.stdout
|
||||
assert 'blockingpage.css missing, replacing... ' not in installWeb.stdout
|
||||
web_directory = Pihole.run('ls -r /var/www/html/pihole').stdout
|
||||
assert 'index.php' in web_directory
|
||||
assert 'index.js' in web_directory
|
||||
assert 'blockingpage.css' in web_directory
|
||||
|
||||
def test_update_package_cache_success_no_errors(Pihole):
|
||||
''' confirms package cache was updated without any errors'''
|
||||
updateCache = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
distro_check
|
||||
update_package_cache
|
||||
''')
|
||||
assert 'Updating local cache of available packages...' in updateCache.stdout
|
||||
assert 'ERROR' not in updateCache.stdout
|
||||
assert 'done!' in updateCache.stdout
|
||||
|
||||
def test_update_package_cache_failure_no_errors(Pihole):
|
||||
''' confirms package cache was not updated'''
|
||||
mock_command('apt-get', {'update':('', '1')}, Pihole)
|
||||
updateCache = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
distro_check
|
||||
update_package_cache
|
||||
''')
|
||||
assert 'Updating local cache of available packages...' in updateCache.stdout
|
||||
assert 'ERROR' in updateCache.stdout
|
||||
assert 'done!' not in updateCache.stdout
|
||||
|
||||
def test_FTL_detect_aarch64_no_errors(Pihole):
|
||||
''' confirms only aarch64 package is downloaded for FTL engine '''
|
||||
# mock uname to return aarch64 platform
|
||||
mock_command('uname', {'-m':('aarch64', '0')}, Pihole)
|
||||
# mock ldd to respond with aarch64 shared library
|
||||
mock_command('ldd', {'/bin/ls':('/lib/ld-linux-aarch64.so.1', '0')}, Pihole)
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
FTLdetect
|
||||
''')
|
||||
expected_stdout = 'Detected ARM-aarch64 architecture'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
def test_FTL_detect_armv6l_no_errors(Pihole):
|
||||
''' confirms only armv6l package is downloaded for FTL engine '''
|
||||
# mock uname to return armv6l platform
|
||||
mock_command('uname', {'-m':('armv6l', '0')}, Pihole)
|
||||
# mock ldd to respond with aarch64 shared library
|
||||
mock_command('ldd', {'/bin/ls':('/lib/ld-linux-armhf.so.3', '0')}, Pihole)
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
FTLdetect
|
||||
''')
|
||||
expected_stdout = 'Detected ARM-hf architecture (armv6 or lower)'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
def test_FTL_detect_armv7l_no_errors(Pihole):
|
||||
''' confirms only armv7l package is downloaded for FTL engine '''
|
||||
# mock uname to return armv7l platform
|
||||
mock_command('uname', {'-m':('armv7l', '0')}, Pihole)
|
||||
# mock ldd to respond with aarch64 shared library
|
||||
mock_command('ldd', {'/bin/ls':('/lib/ld-linux-armhf.so.3', '0')}, Pihole)
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
FTLdetect
|
||||
''')
|
||||
expected_stdout = 'Detected ARM-hf architecture (armv7+)'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
def test_FTL_detect_x86_64_no_errors(Pihole):
|
||||
''' confirms only x86_64 package is downloaded for FTL engine '''
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
FTLdetect
|
||||
''')
|
||||
expected_stdout = 'Detected x86_64 architecture'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
def test_FTL_detect_unknown_no_errors(Pihole):
|
||||
''' confirms only generic package is downloaded for FTL engine '''
|
||||
# mock uname to return generic platform
|
||||
mock_command('uname', {'-m':('mips', '0')}, Pihole)
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
FTLdetect
|
||||
''')
|
||||
expected_stdout = 'Not able to detect architecture (unknown: mips)'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
def test_FTL_download_aarch64_no_errors(Pihole):
|
||||
''' confirms only aarch64 package is downloaded for FTL engine '''
|
||||
# mock uname to return generic platform
|
||||
download_binary = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
FTLinstall pihole-FTL-aarch64-linux-gnu
|
||||
''')
|
||||
expected_stdout = 'done'
|
||||
assert expected_stdout in download_binary.stdout
|
||||
assert 'failed' not in download_binary.stdout
|
||||
|
||||
def test_FTL_download_unknown_fails_no_errors(Pihole):
|
||||
''' confirms unknown binary is not downloaded for FTL engine '''
|
||||
# mock uname to return generic platform
|
||||
download_binary = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
FTLinstall pihole-FTL-mips
|
||||
''')
|
||||
expected_stdout = 'failed'
|
||||
assert expected_stdout in download_binary.stdout
|
||||
assert 'done' not in download_binary.stdout
|
||||
|
||||
def test_FTL_binary_installed_and_responsive_no_errors(Pihole):
|
||||
''' confirms FTL binary is copied and functional in installed location '''
|
||||
installed_binary = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
FTLdetect
|
||||
pihole-FTL version
|
||||
''')
|
||||
expected_stdout = 'v'
|
||||
assert expected_stdout in installed_binary.stdout
|
||||
|
||||
# def test_FTL_support_files_installed(Pihole):
|
||||
# ''' confirms FTL support files are installed '''
|
||||
# support_files = Pihole.run('''
|
||||
# source /opt/pihole/basic-install.sh
|
||||
# FTLdetect
|
||||
# stat -c '%a %n' /var/log/pihole-FTL.log
|
||||
# stat -c '%a %n' /run/pihole-FTL.port
|
||||
# stat -c '%a %n' /run/pihole-FTL.pid
|
||||
# ls -lac /run
|
||||
# ''')
|
||||
# assert '644 /run/pihole-FTL.port' in support_files.stdout
|
||||
# assert '644 /run/pihole-FTL.pid' in support_files.stdout
|
||||
# assert '644 /var/log/pihole-FTL.log' in support_files.stdout
|
||||
|
||||
def test_IPv6_only_link_local(Pihole):
|
||||
''' confirms IPv6 blocking is disabled for Link-local address '''
|
||||
# mock ip -6 address to return Link-local address
|
||||
mock_command_2('ip', {'-6 address':('inet6 fe80::d210:52fa:fe00:7ad7/64 scope link', '0')}, Pihole)
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
useIPv6dialog
|
||||
''')
|
||||
expected_stdout = 'Found neither IPv6 ULA nor GUA address, blocking IPv6 ads will not be enabled'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
def test_IPv6_only_ULA(Pihole):
|
||||
''' confirms IPv6 blocking is enabled for ULA addresses '''
|
||||
# mock ip -6 address to return ULA address
|
||||
mock_command_2('ip', {'-6 address':('inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole)
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
useIPv6dialog
|
||||
''')
|
||||
expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
def test_IPv6_only_GUA(Pihole):
|
||||
''' confirms IPv6 blocking is enabled for GUA addresses '''
|
||||
# mock ip -6 address to return GUA address
|
||||
mock_command_2('ip', {'-6 address':('inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole)
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
useIPv6dialog
|
||||
''')
|
||||
expected_stdout = 'Found IPv6 GUA address, using it for blocking IPv6 ads'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
def test_IPv6_GUA_ULA_test(Pihole):
|
||||
''' confirms IPv6 blocking is enabled for GUA and ULA addresses '''
|
||||
# mock ip -6 address to return GUA and ULA addresses
|
||||
mock_command_2('ip', {'-6 address':('inet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global\ninet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole)
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
useIPv6dialog
|
||||
''')
|
||||
expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
def test_IPv6_ULA_GUA_test(Pihole):
|
||||
''' confirms IPv6 blocking is enabled for GUA and ULA addresses '''
|
||||
# mock ip -6 address to return ULA and GUA addresses
|
||||
mock_command_2('ip', {'-6 address':('inet6 fda2:2001:5555:0:d210:52fa:fe00:7ad7/64 scope global\ninet6 2003:12:1e43:301:d210:52fa:fe00:7ad7/64 scope global', '0')}, Pihole)
|
||||
detectPlatform = Pihole.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
useIPv6dialog
|
||||
''')
|
||||
expected_stdout = 'Found IPv6 ULA address, using it for blocking IPv6 ads'
|
||||
assert expected_stdout in detectPlatform.stdout
|
||||
|
||||
# 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('''\
|
||||
#!/bin/bash -e
|
||||
echo "\$0 \$@" >> /var/log/{script}
|
||||
case "\$1" in'''.format(script=script))
|
||||
for k, v in args.iteritems():
|
||||
case = dedent('''
|
||||
{arg})
|
||||
echo {res}
|
||||
exit {retcode}
|
||||
;;'''.format(arg=k, res=v[0], retcode=v[1]))
|
||||
mock_script += case
|
||||
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))
|
||||
|
||||
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('''\
|
||||
#!/bin/bash -e
|
||||
echo "\$0 \$@" >> /var/log/{script}
|
||||
case "\$1 \$2" in'''.format(script=script))
|
||||
for k, v in args.iteritems():
|
||||
case = dedent('''
|
||||
\"{arg}\")
|
||||
echo \"{res}\"
|
||||
exit {retcode}
|
||||
;;'''.format(arg=k, res=v[0], retcode=v[1]))
|
||||
mock_script += case
|
||||
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))
|
||||
|
||||
def run_script(Pihole, script):
|
||||
result = Pihole.run(script)
|
||||
assert result.rc == 0
|
||||
return result
|
13
test/test_shellcheck.py
Normal file
13
test/test_shellcheck.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import pytest
|
||||
import testinfra
|
||||
|
||||
run_local = testinfra.get_backend(
|
||||
"local://"
|
||||
).get_module("Command").run
|
||||
|
||||
def test_scripts_pass_shellcheck():
|
||||
''' Make sure shellcheck does not find anything wrong with our shell scripts '''
|
||||
shellcheck = "find . -type f \( -name 'update.sh' -o -name 'piholeDebug.sh' \) | while read file; do shellcheck \"$file\"; done;"
|
||||
results = run_local(shellcheck)
|
||||
print results.stdout
|
||||
assert '' == results.stdout
|
Reference in New Issue
Block a user