Compare commits
4847 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ff10fcd0a | ||
|
|
5823f5e254 | ||
|
|
7807a93e10 | ||
|
|
c6a2a6f739 | ||
|
|
241e53ed45 | ||
|
|
d605b4b8f9 | ||
|
|
0e359a6321 | ||
|
|
5bd7cc9c9d | ||
|
|
886f0c7df3 | ||
|
|
3989cc19e9 | ||
|
|
bcb59159ed | ||
|
|
2b52f92647 | ||
|
|
71ed842dfd | ||
|
|
f45248df80 | ||
|
|
5729f64ddc | ||
|
|
2a869419b4 | ||
|
|
4a2f4c1bce | ||
|
|
5ef731fc57 | ||
|
|
71ebd64f4e | ||
|
|
9f0e0dbd37 | ||
|
|
ef30a85afb | ||
|
|
1b809e4e8e | ||
|
|
3d3bb45a46 | ||
|
|
d2a98ae954 | ||
|
|
2e1ce7fc87 | ||
|
|
920cf6de14 | ||
|
|
1eb31174a5 | ||
|
|
ff4487ff74 | ||
|
|
54c58327f1 | ||
|
|
db5e94b14a | ||
|
|
7167e6d5e4 | ||
|
|
39a66b608b | ||
|
|
b06efb6ab7 | ||
|
|
ab4bce4787 | ||
|
|
469c179b32 | ||
|
|
190ab79606 | ||
|
|
669f1b0f4a | ||
|
|
31de661bbb | ||
|
|
3a67d1cf8d | ||
|
|
c0f454ddfa | ||
|
|
ef0a22f9ec | ||
|
|
533a77d6d5 | ||
|
|
76ae75689c | ||
|
|
a780fc59e2 | ||
|
|
28085cf7d8 | ||
|
|
a3cc5df317 | ||
|
|
2eff53b2bb | ||
|
|
8d6ce78c65 | ||
|
|
b52a3a021d | ||
|
|
ae39e338fe | ||
|
|
e243c562c2 | ||
|
|
4c267f7732 | ||
|
|
647ba6ec9d | ||
|
|
ba6d700e7e | ||
|
|
e485a7b9bb | ||
|
|
bfda52ed79 | ||
|
|
941f90d5c1 | ||
|
|
14a379d448 | ||
|
|
671fcaffc3 | ||
|
|
bc8150adfa | ||
|
|
b750b01acc | ||
|
|
996a2c74fa | ||
|
|
d85fee27a9 | ||
|
|
cdd4d9ea9e | ||
|
|
cedd1a2591 | ||
|
|
ac4a975be5 | ||
|
|
996f8fff28 | ||
|
|
e733553295 | ||
|
|
0c4e1b51ab | ||
|
|
c6da1a3918 | ||
|
|
c1eb35a35e | ||
|
|
b5e0f142cc | ||
|
|
8713135b01 | ||
|
|
7cdd8871e5 | ||
|
|
596689b4c9 | ||
|
|
a872fabe7d | ||
|
|
bc21a7155d | ||
|
|
b7bba6a689 | ||
|
|
04f9e92bff | ||
|
|
16fb6665ec | ||
|
|
d84da71310 | ||
|
|
77a30ac0c2 | ||
|
|
56fb954d64 | ||
|
|
99981b5e66 | ||
|
|
19ae9d3ee6 | ||
|
|
d03aa0c0c7 | ||
|
|
3c41ec08a3 | ||
|
|
fdc4cf9869 | ||
|
|
a0ecfcc1dc | ||
|
|
b30d729aa4 | ||
|
|
f8af1a1baa | ||
|
|
ab27a3bd45 | ||
|
|
f3acc7c839 | ||
|
|
6f6b54ea05 | ||
|
|
3cad8e4c5b | ||
|
|
9535e2fd6d | ||
|
|
0ea7344c30 | ||
|
|
55dce14655 | ||
|
|
5bf35dc687 | ||
|
|
c5828df198 | ||
|
|
77e322afa6 | ||
|
|
541257849d | ||
|
|
80560d4a4a | ||
|
|
38bb4a4908 | ||
|
|
2b74b47b4a | ||
|
|
109340033e | ||
|
|
0f246b8df5 | ||
|
|
5b03160295 | ||
|
|
7b0513d1e6 | ||
|
|
466520366d | ||
|
|
9dbcbdbe66 | ||
|
|
a9b9718ffa | ||
|
|
fb073373d6 | ||
|
|
fd050693a2 | ||
|
|
dad6247cb0 | ||
|
|
841222fa21 | ||
|
|
0576810438 | ||
|
|
b755330f4c | ||
|
|
cf59f35a4e | ||
|
|
2131a1fe7f | ||
|
|
a88a94c4f1 | ||
|
|
1c286c7bc4 | ||
|
|
6d670991c3 | ||
|
|
3439045228 | ||
|
|
b710e107d6 | ||
|
|
2673c2c072 | ||
|
|
e393048488 | ||
|
|
2feea70311 | ||
|
|
62f29ba3fa | ||
|
|
89b1cfcd85 | ||
|
|
89e187947e | ||
|
|
d2faa93241 | ||
|
|
0df099a6a5 | ||
|
|
482ac12c9b | ||
|
|
b2592f5d31 | ||
|
|
d0e8b0c962 | ||
|
|
d48d3aba69 | ||
|
|
cbc99d45c6 | ||
|
|
be68a5339c | ||
|
|
606b05eec1 | ||
|
|
a1ee7d92a9 | ||
|
|
6941155572 | ||
|
|
b6d73ac081 | ||
|
|
6fec4acd82 | ||
|
|
b241a19e87 | ||
|
|
a7ba55ffb0 | ||
|
|
115e3eeda9 | ||
|
|
21897d7fbd | ||
|
|
31c7c019cb | ||
|
|
b97f76e678 | ||
|
|
839a70cc37 | ||
|
|
a068567926 | ||
|
|
06fd8123c3 | ||
|
|
c2f3477a82 | ||
|
|
ff64d8cf4d | ||
|
|
e8e8104b36 | ||
|
|
e1dca46423 | ||
|
|
ea5a3bf0b2 | ||
|
|
98867d8d71 | ||
|
|
c88c943cda | ||
|
|
3ef90a9e47 | ||
|
|
58a21bee07 | ||
|
|
676b7e60f3 | ||
|
|
43b88cd628 | ||
|
|
e163ed449d | ||
|
|
ee749f700f | ||
|
|
bb7c7cdf33 | ||
|
|
ffe45e8b76 | ||
|
|
f86ef0128e | ||
|
|
bdab701470 | ||
|
|
1ecb9165ee | ||
|
|
2ff3b95117 | ||
|
|
3ad5097b12 | ||
|
|
d68a2ffaf3 | ||
|
|
913dcead7f | ||
|
|
1358209a9a | ||
|
|
b729a44209 | ||
|
|
5a55fa5e48 | ||
|
|
d419eaf463 | ||
|
|
a8deebde4d | ||
|
|
2ec4e84db4 | ||
|
|
075b3f6468 | ||
|
|
7911841355 | ||
|
|
d2c75a33d5 | ||
|
|
15dfd19f58 | ||
|
|
9ae6b40818 | ||
|
|
aa2da80768 | ||
|
|
b05fc5bb2b | ||
|
|
c99c86af7f | ||
|
|
f552173be3 | ||
|
|
d02aa3ced1 | ||
|
|
d0eb0d5037 | ||
|
|
fbfec961d5 | ||
|
|
fba7517cc6 | ||
|
|
0c125eba2c | ||
|
|
7f4bb24fd3 | ||
|
|
b1ea60484e | ||
|
|
57c40cbd09 | ||
|
|
95d1464e36 | ||
|
|
092e533a30 | ||
|
|
18c6ef8aac | ||
|
|
6be647a85f | ||
|
|
6f7edbc92e | ||
|
|
9beb3a9b6c | ||
|
|
3b6e6317b8 | ||
|
|
a9b5fcd923 | ||
|
|
38d4b2a883 | ||
|
|
e2e7d0a6aa | ||
|
|
aa5c15a728 | ||
|
|
7dea5012ce | ||
|
|
fdca19e66d | ||
|
|
c9e341b5d4 | ||
|
|
012d1e4b3d | ||
|
|
31a096dec2 | ||
|
|
a52a5e7ef2 | ||
|
|
a0d74d1e9d | ||
|
|
0cbf77eb9f | ||
|
|
36470eb138 | ||
|
|
e80e54a61a | ||
|
|
118c0d209d | ||
|
|
9b9e907013 | ||
|
|
4ac4bc5c18 | ||
|
|
8c926d6af6 | ||
|
|
a1d85155fd | ||
|
|
2d0619afec | ||
|
|
ab9d589995 | ||
|
|
4fb5157719 | ||
|
|
641eb7821b | ||
|
|
87f2ae82cd | ||
|
|
469b715442 | ||
|
|
04ffd22b4d | ||
|
|
c120f8a8d8 | ||
|
|
0a5eee4d99 | ||
|
|
2b49988013 | ||
|
|
954b3e784f | ||
|
|
0612685fac | ||
|
|
e3a22dcbfa | ||
|
|
4f660966d0 | ||
|
|
7df22cd8e0 | ||
|
|
01764cc581 | ||
|
|
08cf9aa5a7 | ||
|
|
1ae67e1de8 | ||
|
|
f2cba6cad1 | ||
|
|
df3c46349a | ||
|
|
a2d5b8050a | ||
|
|
01c310a78f | ||
|
|
a9e761ec13 | ||
|
|
761c1cd305 | ||
|
|
6f60555f79 | ||
|
|
c901443676 | ||
|
|
a51be7d498 | ||
|
|
f3ceebbe06 | ||
|
|
57d9b96b53 | ||
|
|
5895690b58 | ||
|
|
d26f8dd665 | ||
|
|
2ba350984f | ||
|
|
60513f93a3 | ||
|
|
3b574096b8 | ||
|
|
58905a1188 | ||
|
|
aa88be335e | ||
|
|
f90dffbf1a | ||
|
|
1fb6366c41 | ||
|
|
4736e03108 | ||
|
|
18bedc0493 | ||
|
|
74948ae5c1 | ||
|
|
9b57f7fa33 | ||
|
|
866045968d | ||
|
|
f2e0cf8a92 | ||
|
|
4c39edbeb9 | ||
|
|
b388ac5bb5 | ||
|
|
7855859726 | ||
|
|
5df7ed2f32 | ||
|
|
25ded79190 | ||
|
|
d3e00f038b | ||
|
|
d5f13018a7 | ||
|
|
c6e3805bbb | ||
|
|
ea451e3c22 | ||
|
|
b97f890a8c | ||
|
|
6198165df8 | ||
|
|
8090071eff | ||
|
|
89c80947df | ||
|
|
b51751e892 | ||
|
|
45d4ab4c22 | ||
|
|
f536718aaa | ||
|
|
f1740da9ff | ||
|
|
9bdbe88a66 | ||
|
|
d25240fe9f | ||
|
|
20b6f9cceb | ||
|
|
f27fd9f899 | ||
|
|
13cf0c1288 | ||
|
|
ae762574e5 | ||
|
|
126b9ae381 | ||
|
|
57fe3b6621 | ||
|
|
56fa9714b5 | ||
|
|
03a8ca5c1b | ||
|
|
78027bd2bf | ||
|
|
7dc7cbb80e | ||
|
|
debc9a69c5 | ||
|
|
1ab193fa9d | ||
|
|
9ec012289f | ||
|
|
c42b97ddb2 | ||
|
|
e5bfafefb9 | ||
|
|
b62495d89e | ||
|
|
c6810a0124 | ||
|
|
8e7670db41 | ||
|
|
7c0c30fb0b | ||
|
|
cbfb58f7a2 | ||
|
|
0c45d23c22 | ||
|
|
3f8fedfb16 | ||
|
|
cbc3fbdfe6 | ||
|
|
020b6b8064 | ||
|
|
523f650157 | ||
|
|
bfee230c79 | ||
|
|
c5ed8f8bed | ||
|
|
66dfa5fc1e | ||
|
|
1791fe22f6 | ||
|
|
a5422dbdf6 | ||
|
|
a2625df5e2 | ||
|
|
7507d533ac | ||
|
|
0944807491 | ||
|
|
a216848c1d | ||
|
|
e033ee6664 | ||
|
|
8c56f54a1e | ||
|
|
6b33b8b4c0 | ||
|
|
ae1a59285d | ||
|
|
0d710fc9e3 | ||
|
|
eb86a5e3b0 | ||
|
|
667e938954 | ||
|
|
41bdb741b7 | ||
|
|
a139af8184 | ||
|
|
60fa93ab47 | ||
|
|
b4102547ac | ||
|
|
ef0bdf6470 | ||
|
|
87cf9add8c | ||
|
|
3a05ac27a2 | ||
|
|
eb5661b553 | ||
|
|
41479524f8 | ||
|
|
357b6702ec | ||
|
|
dfe64d9f51 | ||
|
|
78cdd34992 | ||
|
|
16fb914855 | ||
|
|
20faa1bd1c | ||
|
|
922f795fe6 | ||
|
|
9dc539c98b | ||
|
|
18e4eb460c | ||
|
|
e841347057 | ||
|
|
6deac6dfce | ||
|
|
0d8ece1be2 | ||
|
|
8443262214 | ||
|
|
6993a24224 | ||
|
|
d59eab9a6e | ||
|
|
e47eb30a6e | ||
|
|
641951b3a0 | ||
|
|
db231ded91 | ||
|
|
61f13a334d | ||
|
|
36937b1913 | ||
|
|
d0af1a950b | ||
|
|
a217c75134 | ||
|
|
454c9a411c | ||
|
|
f44b2f6aa3 | ||
|
|
d1539335bc | ||
|
|
44d020a54c | ||
|
|
3e73782f0e | ||
|
|
13cb0c1785 | ||
|
|
49810262db | ||
|
|
58bc98ca44 | ||
|
|
4093959d3e | ||
|
|
06c5fe2a89 | ||
|
|
6cb8f3f403 | ||
|
|
e004d27b28 | ||
|
|
e432fae956 | ||
|
|
0ecb8bf5e9 | ||
|
|
2c689e8642 | ||
|
|
c2fb907490 | ||
|
|
a8e97257d7 | ||
|
|
fee1b8b736 | ||
|
|
f13e0dacde | ||
|
|
0711f4d63a | ||
|
|
d2e9a20d96 | ||
|
|
40ae29f5bf | ||
|
|
31909098f8 | ||
|
|
065e5cb1fe | ||
|
|
d4c33e5188 | ||
|
|
70c48afc04 | ||
|
|
ec5183b553 | ||
|
|
50316ee617 | ||
|
|
c4c8e1e5e1 | ||
|
|
2a82e1fec1 | ||
|
|
be7bfb2cb4 | ||
|
|
8bdcb8ff0d | ||
|
|
541b53229c | ||
|
|
1c2c10c4a5 | ||
|
|
e03585e0bb | ||
|
|
03b15dae35 | ||
|
|
c64b96e2a8 | ||
|
|
cd8120d33f | ||
|
|
809e4bdb1d | ||
|
|
f7982dfbe1 | ||
|
|
e26472756f | ||
|
|
6826d9f316 | ||
|
|
bd982c6f94 | ||
|
|
bd6ca0ad62 | ||
|
|
be03f29a9e | ||
|
|
354c6aab8f | ||
|
|
a7c6eaca5f | ||
|
|
e7d937c412 | ||
|
|
b375dd2c81 | ||
|
|
4abd8196ae | ||
|
|
ae4e41eaaa | ||
|
|
5d2be124a2 | ||
|
|
89d94ac3d1 | ||
|
|
0ae020ef82 | ||
|
|
95a28ae125 | ||
|
|
e5c7549f8f | ||
|
|
4386cc4f22 | ||
|
|
cb49ce38f5 | ||
|
|
3128d14d1f | ||
|
|
bef9cd3bc2 | ||
|
|
60a4814ac1 | ||
|
|
fec1595183 | ||
|
|
3e79e0b1ab | ||
|
|
c80f0766c5 | ||
|
|
fb454ebe14 | ||
|
|
ee556088b5 | ||
|
|
660c17814d | ||
|
|
a7c58e7112 | ||
|
|
05b6717187 | ||
|
|
2c461460db | ||
|
|
5aab68ab41 | ||
|
|
5648ad6b61 | ||
|
|
c9edcfa335 | ||
|
|
33e5735053 | ||
|
|
ad39ba30bd | ||
|
|
50100017a5 | ||
|
|
de02bcc8a0 | ||
|
|
83f2e2d85a | ||
|
|
01c9bbd3ca | ||
|
|
e93d7ad8ff | ||
|
|
59b0a6af6f | ||
|
|
326168509c | ||
|
|
47aa1644a8 | ||
|
|
08a84e51d6 | ||
|
|
d631cd8b04 | ||
|
|
0445559610 | ||
|
|
615b19c3d6 | ||
|
|
948337dd8e | ||
|
|
fe463f15b3 | ||
|
|
716e981a79 | ||
|
|
b88efd2527 | ||
|
|
568ebd67ca | ||
|
|
c628c970ae | ||
|
|
fa0815fb1d | ||
|
|
e9796d5671 | ||
|
|
8041bbf443 | ||
|
|
d6c4f0696f | ||
|
|
b88510d89a | ||
|
|
4d98e156b6 | ||
|
|
5db45aed8b | ||
|
|
b865fa7c0a | ||
|
|
41e899260f | ||
|
|
12b9748c43 | ||
|
|
4fd412d7c3 | ||
|
|
aa7c3b6852 | ||
|
|
17ed5398e6 | ||
|
|
5eabf4255b | ||
|
|
538827397c | ||
|
|
b81cbaa088 | ||
|
|
e02cf6fac5 | ||
|
|
b8cd238fa1 | ||
|
|
8e219cb799 | ||
|
|
65786ba5d6 | ||
|
|
42f55f5202 | ||
|
|
725f02f442 | ||
|
|
ebdb68a47a | ||
|
|
623ce1fe18 | ||
|
|
57e65dd5c0 | ||
|
|
bb1a6243d6 | ||
|
|
ad9b981e8b | ||
|
|
5b1eaa7e38 | ||
|
|
5c72ff75d9 | ||
|
|
cd4072fbf8 | ||
|
|
6b536b7428 | ||
|
|
d4dd446ba3 | ||
|
|
8b4921405a | ||
|
|
492a0317b0 | ||
|
|
b5983a3fc1 | ||
|
|
4bef49e2eb | ||
|
|
27399a762a | ||
|
|
83ecaa0fc9 | ||
|
|
79ff21a2fe | ||
|
|
87da9084e6 | ||
|
|
72df833b8e | ||
|
|
5a48478196 | ||
|
|
8fa9096508 | ||
|
|
319b8eef75 | ||
|
|
7c53b97004 | ||
|
|
18fc45c006 | ||
|
|
fa574cfd08 | ||
|
|
932cdd3329 | ||
|
|
dc2781d1f9 | ||
|
|
48820d181c | ||
|
|
51daeaa6ab | ||
|
|
514dc013df | ||
|
|
548ad6375d | ||
|
|
6fc7dc28a2 | ||
|
|
b207ceeab2 | ||
|
|
8380112129 | ||
|
|
dffb58ae8f | ||
|
|
0ff32c3629 | ||
|
|
dfd331c5b7 | ||
|
|
0a81d687e8 | ||
|
|
dfcdfd4b0a | ||
|
|
ec9f490fcc | ||
|
|
331502e14c | ||
|
|
18c24d985f | ||
|
|
ddb36c013d | ||
|
|
98dc51869e | ||
|
|
510b646736 | ||
|
|
da6b78f4c5 | ||
|
|
61616b8c86 | ||
|
|
be14000778 | ||
|
|
93c1a62998 | ||
|
|
527fc3c5cf | ||
|
|
8f7f0881c6 | ||
|
|
17aabf26f7 | ||
|
|
6ee6eea1fb | ||
|
|
ea22774d16 | ||
|
|
5c9fbd7d1f | ||
|
|
b0ea043b6a | ||
|
|
27366fe9f0 | ||
|
|
25b873cf7b | ||
|
|
643d2c0f3e | ||
|
|
533e5dddd0 | ||
|
|
60f0ab51c9 | ||
|
|
56cd7c4d59 | ||
|
|
f50cff54de | ||
|
|
acfb092e4b | ||
|
|
e9b039139c | ||
|
|
e4b2d29552 | ||
|
|
b4ca13b3ad | ||
|
|
b9b7d5f8eb | ||
|
|
849139176e | ||
|
|
ae0d1de188 | ||
|
|
b8bba7951f | ||
|
|
76ce5ec66b | ||
|
|
7b41b99549 | ||
|
|
0cc999ea1f | ||
|
|
a99eac9d10 | ||
|
|
e76f0119b4 | ||
|
|
a3ae47023f | ||
|
|
6ff0926f4a | ||
|
|
73963fecda | ||
|
|
d8822b70cf | ||
|
|
f50d59fe94 | ||
|
|
cf1c1e2e7e | ||
|
|
f5a5f68a1a | ||
|
|
94cd7f59d4 | ||
|
|
6009e86947 | ||
|
|
56e0549c7a | ||
|
|
49f099e382 | ||
|
|
3205606fc3 | ||
|
|
3aaf9d89b3 | ||
|
|
2c3aa9ab00 | ||
|
|
bf392d7a60 | ||
|
|
9bf0f2a161 | ||
|
|
bbfbf67fcf | ||
|
|
fe30ce10d3 | ||
|
|
3136d239df | ||
|
|
c9350fa76d | ||
|
|
b96ce13085 | ||
|
|
7ea6d7b92b | ||
|
|
011fa8c6ea | ||
|
|
1ebf0785b6 | ||
|
|
0320d85028 | ||
|
|
95f4c632f7 | ||
|
|
4b59287683 | ||
|
|
5f9dac8d2b | ||
|
|
9844a3288f | ||
|
|
03a8cff55e | ||
|
|
c9dd3ee2e9 | ||
|
|
52cb389d94 | ||
|
|
2b1bc6a46e | ||
|
|
6160eb6894 | ||
|
|
318ca75269 | ||
|
|
13a49b0753 | ||
|
|
58724a38a9 | ||
|
|
8fef35be0f | ||
|
|
202ba055ea | ||
|
|
5488fb0caf | ||
|
|
0a47140239 | ||
|
|
7248d1a504 | ||
|
|
7934a9bcb4 | ||
|
|
d90313fe4d | ||
|
|
c73001f392 | ||
|
|
7579ab178a | ||
|
|
903808a477 | ||
|
|
005da06b3d | ||
|
|
852f6b95f5 | ||
|
|
5dc7ec0fa0 | ||
|
|
de8976da7a | ||
|
|
e43450f56e | ||
|
|
4f7bb7b811 | ||
|
|
01ab82b869 | ||
|
|
dd205c55c1 | ||
|
|
b60ec8a48f | ||
|
|
acf2879057 | ||
|
|
27f0fd2372 | ||
|
|
af1129fc28 | ||
|
|
ee172cd6e9 | ||
|
|
d0e250a616 | ||
|
|
b2ba55c27b | ||
|
|
3f83c314b6 | ||
|
|
5094fab491 | ||
|
|
9d04c517e6 | ||
|
|
b421e422c2 | ||
|
|
60afebfd03 | ||
|
|
414ab53d9a | ||
|
|
5c17e41cf1 | ||
|
|
5ce8791693 | ||
|
|
3c6ea2612d | ||
|
|
10addc5923 | ||
|
|
9ee37cb503 | ||
|
|
e1b1512183 | ||
|
|
c76435883b | ||
|
|
2ede032de5 | ||
|
|
8dc8c350be | ||
|
|
ab753e88a2 | ||
|
|
d524f9a73b | ||
|
|
7d79cf5cce | ||
|
|
be25b4d9c4 | ||
|
|
a1e913de7a | ||
|
|
9e96ff37de | ||
|
|
a9c66c7b45 | ||
|
|
2b9898e9ca | ||
|
|
0add5eb291 | ||
|
|
4cf241b42b | ||
|
|
1b41a5d59a | ||
|
|
987ae3810d | ||
|
|
4d25f69526 | ||
|
|
e728d7f761 | ||
|
|
7cc35d3b04 | ||
|
|
78469ee58d | ||
|
|
369288cc48 | ||
|
|
742d802940 | ||
|
|
fdaf815f42 | ||
|
|
988b1ff02f | ||
|
|
df13b9c32a | ||
|
|
4710963ccf | ||
|
|
1540e5bfda | ||
|
|
017d405b28 | ||
|
|
ddb354f78b | ||
|
|
393c7730ec | ||
|
|
4f0e47e927 | ||
|
|
f4965d8493 | ||
|
|
c0cf8dba87 | ||
|
|
a9136d752a | ||
|
|
d7bac21149 | ||
|
|
dc6c53b6a3 | ||
|
|
86d4c9b1e0 | ||
|
|
288d487fc0 | ||
|
|
462457fe7f | ||
|
|
20ef5e0264 | ||
|
|
ad5802715e | ||
|
|
989bbad37e | ||
|
|
63f6c6a894 | ||
|
|
d42785a3bf | ||
|
|
401c029dc4 | ||
|
|
ed9d74593d | ||
|
|
9286965ee2 | ||
|
|
fa57c457f3 | ||
|
|
0343171703 | ||
|
|
176fbaf83b | ||
|
|
94a4f844a8 | ||
|
|
d18a8b1b8a | ||
|
|
a37dba2c81 | ||
|
|
471006676c | ||
|
|
0155d42650 | ||
|
|
e80990c27a | ||
|
|
e6dcccc7bd | ||
|
|
3cc9ba4ee8 | ||
|
|
6dc85c3527 | ||
|
|
7e1a8c1ceb | ||
|
|
4f01daf5bc | ||
|
|
0f20470a38 | ||
|
|
851947bbf2 | ||
|
|
413fa94e98 | ||
|
|
308eb5eda5 | ||
|
|
093054a1eb | ||
|
|
4130af0aab | ||
|
|
90a5a13197 | ||
|
|
1632632668 | ||
|
|
982c1b0059 | ||
|
|
26f71e4dbe | ||
|
|
b6ac1585ec | ||
|
|
a9b19df4ec | ||
|
|
d27a565d39 | ||
|
|
2de5362adc | ||
|
|
de42669bb7 | ||
|
|
3095fd4dd6 | ||
|
|
ebbb7168a4 | ||
|
|
40ac3e7eb7 | ||
|
|
25c5661c1b | ||
|
|
a993b8b34d | ||
|
|
16f664cdb4 | ||
|
|
a2d2639ee8 | ||
|
|
d1caad76d8 | ||
|
|
fff7adfb20 | ||
|
|
7d19ee1b25 | ||
|
|
7b15a88dc4 | ||
|
|
dc35709a1b | ||
|
|
0fad979206 | ||
|
|
277179f150 | ||
|
|
15a9d662ac | ||
|
|
1b35eebad8 | ||
|
|
6d4844a0b3 | ||
|
|
4994da5170 | ||
|
|
175d32c5f6 | ||
|
|
1481cc583f | ||
|
|
dbc54b3063 | ||
|
|
bb936f4fdb | ||
|
|
7b8611ced0 | ||
|
|
497bfd80a5 | ||
|
|
22ce5c0d70 | ||
|
|
4a711340ef | ||
|
|
f617ed2f44 | ||
|
|
bf4fada3b7 | ||
|
|
360d0e4e6b | ||
|
|
4f390ce801 | ||
|
|
027b97cbfa | ||
|
|
d16b472592 | ||
|
|
6e67124770 | ||
|
|
e6bfb0fe17 | ||
|
|
dc8ae4f0ab | ||
|
|
d2a8b4d2b9 | ||
|
|
c07d86b9f9 | ||
|
|
9e490775ff | ||
|
|
58785020bd | ||
|
|
1c74b41869 | ||
|
|
6104d81622 | ||
|
|
121c93e822 | ||
|
|
b4c2bf678f | ||
|
|
14944b0283 | ||
|
|
8ecaaba247 | ||
|
|
0fbcc6d8b5 | ||
|
|
707e21b927 | ||
|
|
f4a1cc6dec | ||
|
|
3dd05606ca | ||
|
|
1e8bfd33f5 | ||
|
|
545b6605bc | ||
|
|
8131b5961c | ||
|
|
81d4531e10 | ||
|
|
050e2963c7 | ||
|
|
3c09cd4a3a | ||
|
|
839fe32042 | ||
|
|
85c15a7167 | ||
|
|
b73580fa93 | ||
|
|
4a5f344b09 | ||
|
|
af95e8c250 | ||
|
|
ee7090b8fc | ||
|
|
7be019ff52 | ||
|
|
d14ee26d6a | ||
|
|
52398052e9 | ||
|
|
ddbd57f459 | ||
|
|
601f9048cd | ||
|
|
c5c414a7a2 | ||
|
|
bc91be6c08 | ||
|
|
d0e29ab7b0 | ||
|
|
714a79ffce | ||
|
|
cd3ad0bdc7 | ||
|
|
a8db753493 | ||
|
|
75633f0950 | ||
|
|
082cfb2f1c | ||
|
|
1072078e26 | ||
|
|
b0f1333657 | ||
|
|
f10a151469 | ||
|
|
eadd82761c | ||
|
|
00f4393f48 | ||
|
|
50f6fffbdc | ||
|
|
baf5340dc0 | ||
|
|
e528903488 | ||
|
|
dc2fce8e1d | ||
|
|
c4005c4a31 | ||
|
|
0a70bbd255 | ||
|
|
c91d9cc0b6 | ||
|
|
8e10c22356 | ||
|
|
37a44c0773 | ||
|
|
2a5cf221fa | ||
|
|
92aa510bda | ||
|
|
6b04997fc3 | ||
|
|
e0b3405a4d | ||
|
|
10c2dad48a | ||
|
|
52e2a2610e | ||
|
|
a809624356 | ||
|
|
29f06a4444 | ||
|
|
3f9e79f152 | ||
|
|
633e56e8a9 | ||
|
|
bf01f725f7 | ||
|
|
276b191845 | ||
|
|
c7bc58e94b | ||
|
|
8f22203d24 | ||
|
|
782fec841e | ||
|
|
cfa909a93d | ||
|
|
e0fde41d87 | ||
|
|
574f7c1a1f | ||
|
|
ec8f4050d0 | ||
|
|
60c51886e0 | ||
|
|
cbb1461010 | ||
|
|
07cc5b501c | ||
|
|
ebb1a730c1 | ||
|
|
9dff55b212 | ||
|
|
8ae03b64d7 | ||
|
|
bb30c818ab | ||
|
|
c944f6a320 | ||
|
|
62ec7de963 | ||
|
|
aa4c0ff329 | ||
|
|
37217ece73 | ||
|
|
28d4f4b142 | ||
|
|
8d5d423adb | ||
|
|
cda0133dd1 | ||
|
|
eda7f40fef | ||
|
|
e589e665a7 | ||
|
|
b32b5ad6e9 | ||
|
|
e2de199f47 | ||
|
|
948f4a8827 | ||
|
|
a1633123aa | ||
|
|
2444296348 | ||
|
|
4be7ebe61f | ||
|
|
a720fe1789 | ||
|
|
2cec9eaf65 | ||
|
|
313f999af4 | ||
|
|
0b0ec43bf5 | ||
|
|
f0439c8d12 | ||
|
|
40e8657137 | ||
|
|
52dd72dfa5 | ||
|
|
922ce7359c | ||
|
|
779fe670f7 | ||
|
|
570a7a5c11 | ||
|
|
bd1b004d94 | ||
|
|
5457b2c6ea | ||
|
|
02f3316710 | ||
|
|
69a909fc4c | ||
|
|
ec09b5843c | ||
|
|
078e7e1686 | ||
|
|
d29947ba32 | ||
|
|
1f03faddef | ||
|
|
d1bce7e685 | ||
|
|
880352ea65 | ||
|
|
3231e5c3ba | ||
|
|
f482156cca | ||
|
|
620e1e9c73 | ||
|
|
8a119d72e2 | ||
|
|
807a5cfb23 | ||
|
|
54d0b9a1b8 | ||
|
|
ca7a5bc0fe | ||
|
|
0c5185f8ba | ||
|
|
eaf1244932 | ||
|
|
7c2bbf840a | ||
|
|
85673b8273 | ||
|
|
b6cd7b8e3d | ||
|
|
869473172c | ||
|
|
63e407cfdc | ||
|
|
0251117c77 | ||
|
|
44e1455b12 | ||
|
|
76460f01e9 | ||
|
|
4b8a72fda7 | ||
|
|
edaee4e962 | ||
|
|
77bfb3fb67 | ||
|
|
6a881545b0 | ||
|
|
d0de5fda30 | ||
|
|
a1f120b2ff | ||
|
|
185319d560 | ||
|
|
5c6dd3f6f4 | ||
|
|
8e5abc1f15 | ||
|
|
9248c92b5c | ||
|
|
583ea4d17a | ||
|
|
edcdf9f619 | ||
|
|
c809c34024 | ||
|
|
037d52104a | ||
|
|
1fb70c977c | ||
|
|
eeb26e3975 | ||
|
|
12817c09bb | ||
|
|
4840bdb031 | ||
|
|
a85e7a2a43 | ||
|
|
b93628acb3 | ||
|
|
7f7b9d089c | ||
|
|
61d233f069 | ||
|
|
d457d40e0b | ||
|
|
6571a63ffa | ||
|
|
a7e81c8ea0 | ||
|
|
73d9abae3e | ||
|
|
c8b9e42649 | ||
|
|
62c00ae1d8 | ||
|
|
ea67c828cd | ||
|
|
476975540a | ||
|
|
3fbb0ac8dd | ||
|
|
71903eb27f | ||
|
|
193ff38ab3 | ||
|
|
bb8dbe9da5 | ||
|
|
f9d16c2b15 | ||
|
|
29bad2fe9b | ||
|
|
f4aca3f21d | ||
|
|
c6f9fe3af2 | ||
|
|
612d408034 | ||
|
|
a86f578139 | ||
|
|
5bac1ad58b | ||
|
|
cf2b021502 | ||
|
|
cd9b1fcb8c | ||
|
|
81ca78e7f4 | ||
|
|
fc0899b2ad | ||
|
|
2e138eb99f | ||
|
|
4f21f67775 | ||
|
|
d883854aad | ||
|
|
756c99653e | ||
|
|
3269c63f89 | ||
|
|
149fb0c216 | ||
|
|
d244a018d0 | ||
|
|
2e0370367c | ||
|
|
3cb4f6d9d4 | ||
|
|
ae3b8be4d4 | ||
|
|
61a40c1b43 | ||
|
|
a27c7b1398 | ||
|
|
a71f35d263 | ||
|
|
9a6deb5a1a | ||
|
|
f582344b9a | ||
|
|
e41c4b5bb6 | ||
|
|
7b48431917 | ||
|
|
847c4f26aa | ||
|
|
1f36ec48e3 | ||
|
|
ff08add7c0 | ||
|
|
b4131ae817 | ||
|
|
ffc91a6c81 | ||
|
|
525ec8cd01 | ||
|
|
b209629579 | ||
|
|
a8af2e1837 | ||
|
|
93ecc046ea | ||
|
|
8bef5dc805 | ||
|
|
ad41bcca5a | ||
|
|
aed2e35bc0 | ||
|
|
ab90ff565a | ||
|
|
ca8982494b | ||
|
|
a7b44426cd | ||
|
|
e7af42a9f8 | ||
|
|
b9fed8fca6 | ||
|
|
79b8dac0fa | ||
|
|
d8eee47ca4 | ||
|
|
a3e32d9a15 | ||
|
|
989d1aff60 | ||
|
|
95b2560a08 | ||
|
|
76133074d1 | ||
|
|
4cfe463dfa | ||
|
|
03c65dd0e9 | ||
|
|
6faddfcd3d | ||
|
|
1820c2c598 | ||
|
|
23b688287f | ||
|
|
42ccc1ef24 | ||
|
|
aef7892de6 | ||
|
|
cc40c18f49 | ||
|
|
b1838512b2 | ||
|
|
1c50caa8ca | ||
|
|
febdbceab1 | ||
|
|
597b4bfcca | ||
|
|
5c65006a66 | ||
|
|
34727c00c6 | ||
|
|
352146ef92 | ||
|
|
b107ae2ab9 | ||
|
|
d5d1a607ad | ||
|
|
2594164772 | ||
|
|
209555c42e | ||
|
|
e27f50b8e5 | ||
|
|
484f618685 | ||
|
|
da398c3d9c | ||
|
|
4e0ad52001 | ||
|
|
c9829dd3e4 | ||
|
|
35cf863f4b | ||
|
|
c53be459c6 | ||
|
|
ab1ea5a366 | ||
|
|
97e11bd94e | ||
|
|
10de7f649b | ||
|
|
d793ef1ab8 | ||
|
|
d3d45a8776 | ||
|
|
9f86fd0cb4 | ||
|
|
71d5b42726 | ||
|
|
3e78ed95d4 | ||
|
|
20a839fef5 | ||
|
|
b2d8c4374b | ||
|
|
251c9fee98 | ||
|
|
9f77810ca8 | ||
|
|
dc93462d42 | ||
|
|
4371c9ba03 | ||
|
|
6e2e825a5f | ||
|
|
af754e3fc4 | ||
|
|
06860ed5b4 | ||
|
|
09190c1735 | ||
|
|
a95b473417 | ||
|
|
56e3565a9e | ||
|
|
63230cb72d | ||
|
|
f81e57d5b8 | ||
|
|
ecd6817aaf | ||
|
|
6f58d58cae | ||
|
|
40d0caa70b | ||
|
|
0692be9bae | ||
|
|
0d28dce326 | ||
|
|
96031214c6 | ||
|
|
3420439f31 | ||
|
|
ab3f6dfcc6 | ||
|
|
3ebd43ebf0 | ||
|
|
38ff343134 | ||
|
|
6a8d3100d2 | ||
|
|
c3ec2e68ad | ||
|
|
bfe714e985 | ||
|
|
1d5755a4c2 | ||
|
|
445127accc | ||
|
|
c156af020c | ||
|
|
fa8751f9ad | ||
|
|
420f60b5c7 | ||
|
|
65fdbc85d5 | ||
|
|
87f75c737a | ||
|
|
5ff9052200 | ||
|
|
9641e268ea | ||
|
|
b154dd5f07 | ||
|
|
0683842ec3 | ||
|
|
f5121c64be | ||
|
|
054c7a2c05 | ||
|
|
3d3fc2947e | ||
|
|
e8e5d4afda | ||
|
|
8382f4d727 | ||
|
|
be3e198f9a | ||
|
|
acc50b709e | ||
|
|
5a6763f90d | ||
|
|
218476fab0 | ||
|
|
ec850dc820 | ||
|
|
c48b03584f | ||
|
|
efe8216445 | ||
|
|
0405aaa3da | ||
|
|
6bb213e56f | ||
|
|
2fb4256f84 | ||
|
|
82476138c1 | ||
|
|
5293beeb77 | ||
|
|
0c8f5f1221 | ||
|
|
4f4a12bb40 | ||
|
|
1dbe6c83c3 | ||
|
|
2b5033e732 | ||
|
|
8d9ff550d4 | ||
|
|
f1733f9c5d | ||
|
|
92c3c86be4 | ||
|
|
ada8b53423 | ||
|
|
7a1b6fd205 | ||
|
|
b78cbb98d8 | ||
|
|
04abcb71f6 | ||
|
|
1fe3507bc5 | ||
|
|
9fedafed15 | ||
|
|
23b3a9a650 | ||
|
|
7b2ac25a52 | ||
|
|
f91421418a | ||
|
|
3a14e8b013 | ||
|
|
ad97e95f2f | ||
|
|
5b01facd73 | ||
|
|
6fe637b9ee | ||
|
|
94d83dbb2d | ||
|
|
c9a843b417 | ||
|
|
b986c5585d | ||
|
|
87c115fc86 | ||
|
|
acee97916e | ||
|
|
1a741f696e | ||
|
|
37e7cd5211 | ||
|
|
91a2d052a7 | ||
|
|
06134d3ffc | ||
|
|
092957c14a | ||
|
|
d5e8f1a781 | ||
|
|
b5af125be6 | ||
|
|
ecc49318f0 | ||
|
|
974bba4a45 | ||
|
|
951732fc1b | ||
|
|
b6700924b2 | ||
|
|
5d43639e93 | ||
|
|
27e4208631 | ||
|
|
b505ad22e6 | ||
|
|
d67122dffc | ||
|
|
0774c4e5ca | ||
|
|
01850c2128 | ||
|
|
cbc210b014 | ||
|
|
c53ee4202b | ||
|
|
f2be12f97b | ||
|
|
6996ffa451 | ||
|
|
435a5fb3ad | ||
|
|
4947350ca5 | ||
|
|
c1495b0fa8 | ||
|
|
67dda9c8bb | ||
|
|
c8987e20c2 | ||
|
|
bcf03647ef | ||
|
|
a9d0690f4d | ||
|
|
10fbed50f3 | ||
|
|
785f1fedd9 | ||
|
|
b0c5dcf42f | ||
|
|
cf21efa103 | ||
|
|
7613e94ef6 | ||
|
|
b49c702f33 | ||
|
|
09532638d5 | ||
|
|
97df6d7415 | ||
|
|
54bfaa28c1 | ||
|
|
a09f92f9cc | ||
|
|
afd28fab03 | ||
|
|
d92ced6fb6 | ||
|
|
ae98fde321 | ||
|
|
9ddce88092 | ||
|
|
44f8fcb600 | ||
|
|
814fdcf9b6 | ||
|
|
5060605626 | ||
|
|
453ba14cbd | ||
|
|
285e6fe090 | ||
|
|
c3023fe681 | ||
|
|
c5df104a66 | ||
|
|
f6213d4f4d | ||
|
|
ca2ea388b7 | ||
|
|
69dba022c4 | ||
|
|
bfb99c361c | ||
|
|
5796054305 | ||
|
|
a3e1473ac1 | ||
|
|
7b5fc60e00 | ||
|
|
807ce0af4e | ||
|
|
3f05efd60f | ||
|
|
03d93aa19a | ||
|
|
cad9386ff6 | ||
|
|
7de6bbca61 | ||
|
|
1d43c0a2fa | ||
|
|
c8d32e0dd3 | ||
|
|
be3a21ae07 | ||
|
|
69081a9175 | ||
|
|
ab2f8a0c09 | ||
|
|
b961a501bb | ||
|
|
8e1bf6e3d4 | ||
|
|
d6756eb46b | ||
|
|
efbd42f7b5 | ||
|
|
3f90261520 | ||
|
|
ff5894d772 | ||
|
|
225285cb97 | ||
|
|
3220e2b978 | ||
|
|
54ae458b61 | ||
|
|
e076db5a4e | ||
|
|
a3d2a1062f | ||
|
|
2e6198077d | ||
|
|
55ab3b2dc7 | ||
|
|
bdc8cf2bc8 | ||
|
|
74836bebe4 | ||
|
|
95150a5d85 | ||
|
|
4d23b3267f | ||
|
|
e19adccd9c | ||
|
|
a25f331e83 | ||
|
|
69c06ba6fe | ||
|
|
8abeb2204b | ||
|
|
ec06fd0ad4 | ||
|
|
a904c183df | ||
|
|
5246b3e496 | ||
|
|
f80fdd7e83 | ||
|
|
6ba58896d2 | ||
|
|
3aa838bbe4 | ||
|
|
2c3a27e9c7 | ||
|
|
5532df24e4 | ||
|
|
b3898b9b2a | ||
|
|
9ce84714cd | ||
|
|
0bc112ce52 | ||
|
|
d46ff1d2d7 | ||
|
|
0cfecd31d3 | ||
|
|
008e88b84b | ||
|
|
2f698904e4 | ||
|
|
106f079afc | ||
|
|
6c1e3a17f7 | ||
|
|
540c57f755 | ||
|
|
5e26e8245b | ||
|
|
983117d788 | ||
|
|
b372f808dd | ||
|
|
bc9b623638 | ||
|
|
d5781fb110 | ||
|
|
487718512d | ||
|
|
8a92fb24c4 | ||
|
|
5c575e73c7 | ||
|
|
2180531a84 | ||
|
|
6812e8880e | ||
|
|
a932209143 | ||
|
|
4946b5907b | ||
|
|
efeba594ae | ||
|
|
b27e4c3dc3 | ||
|
|
5e1241acd2 | ||
|
|
126f7101ff | ||
|
|
b320e74921 | ||
|
|
add5e4ca5e | ||
|
|
466fd79c66 | ||
|
|
4596d9a577 | ||
|
|
b4ae142149 | ||
|
|
3fe43ce1d9 | ||
|
|
8524aecfed | ||
|
|
e04dc9d2bb | ||
|
|
3dcb9722d3 | ||
|
|
bd0215524b | ||
|
|
53e3ff2b24 | ||
|
|
5bb8163674 | ||
|
|
a891d64395 | ||
|
|
6b1d2523e8 | ||
|
|
08ee9526ad | ||
|
|
0efc46260f | ||
|
|
6a01a1257f | ||
|
|
a2a7e80007 | ||
|
|
cce66a13b6 | ||
|
|
43bced7997 | ||
|
|
788cd78321 | ||
|
|
e5d1cb5a2e | ||
|
|
d94bbfca7f | ||
|
|
465a39427b | ||
|
|
2664ac0efc | ||
|
|
c1277705d8 | ||
|
|
61cfd2f9f9 | ||
|
|
ee4dabeca6 | ||
|
|
e57d0fb93c | ||
|
|
ee20164207 | ||
|
|
d7ee44960e | ||
|
|
c13ebd3a9d | ||
|
|
6594a0a6e7 | ||
|
|
de44563301 | ||
|
|
e3d9cf0ac1 | ||
|
|
bd572d8843 | ||
|
|
037737d653 | ||
|
|
d2c7c426de | ||
|
|
1d09c6e47d | ||
|
|
84244b7cd5 | ||
|
|
422680ee9f | ||
|
|
42c7653e99 | ||
|
|
78c0c58946 | ||
|
|
cae61614f4 | ||
|
|
a7f6c9b3a0 | ||
|
|
5950b4bb78 | ||
|
|
817b19888f | ||
|
|
b64fb578fc | ||
|
|
e9e92368b0 | ||
|
|
ffcb173a7f | ||
|
|
b9c9c2797f | ||
|
|
204a4e459b | ||
|
|
0a53e966ea | ||
|
|
2e17c23333 | ||
|
|
63f3381a2b | ||
|
|
2292720fed | ||
|
|
b77efa521f | ||
|
|
cfe221706b | ||
|
|
54ae9d83b0 | ||
|
|
293e2a8e80 | ||
|
|
71cd6c137b | ||
|
|
0e14d11a20 | ||
|
|
bbc392caeb | ||
|
|
61840edb30 | ||
|
|
9867b7fccf | ||
|
|
58f198626a | ||
|
|
a145f1d931 | ||
|
|
9748f19172 | ||
|
|
ba1e94d3d9 | ||
|
|
cd9fadbc44 | ||
|
|
062a180a1c | ||
|
|
860ec1a7c4 | ||
|
|
5ca1bfc11c | ||
|
|
2f189cd076 | ||
|
|
2f0e6a6dda | ||
|
|
f187b42a98 | ||
|
|
f9250d91a5 | ||
|
|
491c828661 | ||
|
|
644ec36e64 | ||
|
|
838e1b19ec | ||
|
|
d5bbb2b640 | ||
|
|
dc91d4b1f9 | ||
|
|
9984647ebb | ||
|
|
ec5b16ef85 | ||
|
|
c3c60e10f1 | ||
|
|
8a2363621d | ||
|
|
dbbf21071b | ||
|
|
e967fe2266 | ||
|
|
b5c7657e01 | ||
|
|
680d6e2d31 | ||
|
|
7a19d24058 | ||
|
|
995ee41d6b | ||
|
|
b2f4385232 | ||
|
|
1f9a7d0b0c | ||
|
|
d5feffa117 | ||
|
|
fc62cf7e2f | ||
|
|
93f1859bab | ||
|
|
dcf0a605cf | ||
|
|
710036adae | ||
|
|
8a91fe6992 | ||
|
|
09c4c88a6d | ||
|
|
69919ac85c | ||
|
|
26f2410fe6 | ||
|
|
d43c32e9e8 | ||
|
|
5c4ee23795 | ||
|
|
fb3d871553 | ||
|
|
ae654730c4 | ||
|
|
ec79e86bee | ||
|
|
e8dabc71af | ||
|
|
9c0de0f731 | ||
|
|
4948862dce | ||
|
|
7479485d45 | ||
|
|
1e284f69ea | ||
|
|
516ed83638 | ||
|
|
26361883b4 | ||
|
|
d26f2dcb2c | ||
|
|
cc657c0c26 | ||
|
|
d90d7b6927 | ||
|
|
de6dc90575 | ||
|
|
3cdd6204c5 | ||
|
|
d996e9c9ee | ||
|
|
a4ba8d4b8f | ||
|
|
cd8a423b32 | ||
|
|
f7ca74cf1d | ||
|
|
ebba32e1c4 | ||
|
|
e02da90faa | ||
|
|
0de5132e2b | ||
|
|
7d2507527a | ||
|
|
97decb3a73 | ||
|
|
f360959efc | ||
|
|
465589c0fd | ||
|
|
9fcf7a2610 | ||
|
|
3035fbf468 | ||
|
|
c4c354bc4b | ||
|
|
c5da1bb952 | ||
|
|
486c41a69a | ||
|
|
87800a3659 | ||
|
|
d5fbe1b629 | ||
|
|
a3cee67a61 | ||
|
|
5ffc8c7443 | ||
|
|
04fd296ffe | ||
|
|
262d5eea22 | ||
|
|
ed5869646f | ||
|
|
b984fc4e0e | ||
|
|
0ef4901e48 | ||
|
|
8d85d46c1a | ||
|
|
eca975a370 | ||
|
|
3bb94d469d | ||
|
|
724afc000f | ||
|
|
be2d494fcf | ||
|
|
a36734db66 | ||
|
|
1cad069050 | ||
|
|
d24e0a6060 | ||
|
|
f65f793a0d | ||
|
|
f7ad489805 | ||
|
|
62459c4f00 | ||
|
|
05bd88b4d8 | ||
|
|
0546fff1ce | ||
|
|
83f7bd66e6 | ||
|
|
14ebb2fb93 | ||
|
|
916b2920be | ||
|
|
a20963889c | ||
|
|
4b77475807 | ||
|
|
9f672593bc | ||
|
|
a285ae65fb | ||
|
|
917a0239a9 | ||
|
|
3261c2e273 | ||
|
|
d0125d5aad | ||
|
|
65a3da92f1 | ||
|
|
5c621fa253 | ||
|
|
f9e71bee0a | ||
|
|
c3804877ed | ||
|
|
35e53ab9c7 | ||
|
|
053987b9e1 | ||
|
|
c0bc93c7c4 | ||
|
|
1f596eb2bc | ||
|
|
3f59b51be1 | ||
|
|
9d59da8974 | ||
|
|
51218bd1ad | ||
|
|
e1c3c53058 | ||
|
|
9fa497b056 | ||
|
|
057fbfc2b9 | ||
|
|
33156071cd | ||
|
|
bbb759c684 | ||
|
|
f1a7bc9ecd | ||
|
|
d514608f91 | ||
|
|
e8c2e26358 | ||
|
|
61c67849d7 | ||
|
|
2cdbb34763 | ||
|
|
538ba918c1 | ||
|
|
c330df9700 | ||
|
|
1789a2db29 | ||
|
|
c270b83341 | ||
|
|
02f0788033 | ||
|
|
a2ea6e8d47 | ||
|
|
a986f53134 | ||
|
|
9d2d45b473 | ||
|
|
0c892e6b3a | ||
|
|
a0fc38d6a2 | ||
|
|
28cbf45d1d | ||
|
|
72829be281 | ||
|
|
d57f9906bd | ||
|
|
3d4fea6510 | ||
|
|
f670644954 | ||
|
|
dd6821814a | ||
|
|
f33584511c | ||
|
|
3ec84553ef | ||
|
|
a301d4381f | ||
|
|
49b8ad7e94 | ||
|
|
180d29c7b3 | ||
|
|
a23ba91681 | ||
|
|
d986da63a5 | ||
|
|
d3ac8bb6f8 | ||
|
|
f87f3b9199 | ||
|
|
67bdcbcf19 | ||
|
|
69b2a5a876 | ||
|
|
a79dff3d98 | ||
|
|
c859a23136 | ||
|
|
7f92671765 | ||
|
|
ec38105b08 | ||
|
|
85dceb12a1 | ||
|
|
5126c37c1e | ||
|
|
e7e03e36de | ||
|
|
13c393fc9d | ||
|
|
cc2f375b13 | ||
|
|
49d5109c96 | ||
|
|
e5c8f5e2fa | ||
|
|
ff925a7578 | ||
|
|
33939a30ea | ||
|
|
308b296285 | ||
|
|
d55012f724 | ||
|
|
7c6eecc9c8 | ||
|
|
e4cbf5023a | ||
|
|
46356d3027 | ||
|
|
958a263437 | ||
|
|
a89ae82270 | ||
|
|
cedc39bf09 | ||
|
|
0131055ec9 | ||
|
|
0627e68078 | ||
|
|
7d78f6314a | ||
|
|
0f509f4a34 | ||
|
|
b043000044 | ||
|
|
c338eab3c6 | ||
|
|
24e1dc92ba | ||
|
|
00f98543ad | ||
|
|
8684356b44 | ||
|
|
a89615365e | ||
|
|
3c36c22ca8 | ||
|
|
7a2f5f43f9 | ||
|
|
dac27f1f18 | ||
|
|
6f276ae4bb | ||
|
|
537e288758 | ||
|
|
3cea1bd423 | ||
|
|
c976bbcfd2 | ||
|
|
ec29829550 | ||
|
|
cf7180af5b | ||
|
|
c58e3acc78 | ||
|
|
b78aef1e7e | ||
|
|
f20e4ddf3b | ||
|
|
40656641b6 | ||
|
|
6f8e8e98bb | ||
|
|
24b4aabae9 | ||
|
|
a9c6d79cda | ||
|
|
45bf4b02e7 | ||
|
|
667c5138cc | ||
|
|
85cf98888d | ||
|
|
048e5bb9a2 | ||
|
|
b9d47d0dd2 | ||
|
|
1813c25117 | ||
|
|
940c9c3bae | ||
|
|
5d0d7336ff | ||
|
|
6a26a05dbf | ||
|
|
c22e94c9c7 | ||
|
|
4aafa8cf47 | ||
|
|
9235a11d5f | ||
|
|
f141b9f778 | ||
|
|
1dca1efbc6 | ||
|
|
28c6b1393f | ||
|
|
6c97b8b875 | ||
|
|
ec2426b24d | ||
|
|
5cd3b11391 | ||
|
|
d30b565d98 | ||
|
|
74008d28a7 | ||
|
|
0d1b3cee4f | ||
|
|
0b44cb4426 | ||
|
|
eb8e4496b2 | ||
|
|
30f45d4df7 | ||
|
|
24e1c78d52 | ||
|
|
476fecbcf5 | ||
|
|
327b58fa03 | ||
|
|
d3eea9404d | ||
|
|
ca309d3b28 | ||
|
|
0ebd68f17f | ||
|
|
3696373609 | ||
|
|
165affc39b | ||
|
|
f794018e0c | ||
|
|
337cc5ca18 | ||
|
|
4e4d6b5d1f | ||
|
|
b011adc453 | ||
|
|
d8abc1d266 | ||
|
|
6cde066edd | ||
|
|
d163e38380 | ||
|
|
d9195970b7 | ||
|
|
20b946eae5 | ||
|
|
c00357663b | ||
|
|
2feb5f22cc | ||
|
|
f3aee056ad | ||
|
|
91ff5ca0ca | ||
|
|
4238e36d7f | ||
|
|
03a9d3bc5b | ||
|
|
fe46dee194 | ||
|
|
1c6c35f861 | ||
|
|
926b25fd54 | ||
|
|
e58142b4ac | ||
|
|
3e5c6afaee | ||
|
|
a1bf9fad98 | ||
|
|
afdc4219d0 | ||
|
|
94e4ed6644 | ||
|
|
ef8aaba014 | ||
|
|
d2ae07e69b | ||
|
|
760dd01b50 | ||
|
|
5bf90cb77d | ||
|
|
f5c3dc5d9d | ||
|
|
f2b820079a | ||
|
|
083024496a | ||
|
|
e01eea8ba8 | ||
|
|
eef948d797 | ||
|
|
8017be7d09 | ||
|
|
5b628a4c77 | ||
|
|
ddbdb51d20 | ||
|
|
0081a7ca92 | ||
|
|
e80ae4906f | ||
|
|
e4e22fb58e | ||
|
|
7086a400e8 | ||
|
|
a25a13fde0 | ||
|
|
993beab3b7 | ||
|
|
06875f2cc9 | ||
|
|
448fc7231c | ||
|
|
d0d030bafc | ||
|
|
833131e15f | ||
|
|
fb2810557a | ||
|
|
82a64db42b | ||
|
|
57af0ba0a4 | ||
|
|
17c1e64f7e | ||
|
|
af13ceac24 | ||
|
|
af2ec61965 | ||
|
|
a55cc55338 | ||
|
|
b2fb3fd35a | ||
|
|
94b7c8eb59 | ||
|
|
6d671007dd | ||
|
|
1a8d5fb4a9 | ||
|
|
f90c412b35 | ||
|
|
c73b5456eb | ||
|
|
3d87398721 | ||
|
|
96681887b8 | ||
|
|
f2c675cff6 | ||
|
|
1844bf17a7 | ||
|
|
47b56d6123 | ||
|
|
814d5f6d6c | ||
|
|
512d2dd5f8 | ||
|
|
ad20d5ac1c | ||
|
|
b79ff05e29 | ||
|
|
32b50f8188 | ||
|
|
a44096a26d | ||
|
|
32cf94fc74 | ||
|
|
39e28cd80a | ||
|
|
9b1356ad01 | ||
|
|
45521b377a | ||
|
|
46a366635c | ||
|
|
384b588a2d | ||
|
|
03e5a78d8f | ||
|
|
e32c76b059 | ||
|
|
ba7782f867 | ||
|
|
c5091b0e49 | ||
|
|
b54e32f0ca | ||
|
|
328e7738d5 | ||
|
|
aca359c2e2 | ||
|
|
1cd40dc9e5 | ||
|
|
dc9407281f | ||
|
|
8f727c1f35 | ||
|
|
a08ea28feb | ||
|
|
c5535dd9a0 | ||
|
|
3519cc5e44 | ||
|
|
d251bbbb05 | ||
|
|
1fc3ec9029 | ||
|
|
1877128fc4 | ||
|
|
76c5b4a06b | ||
|
|
9cd674b528 | ||
|
|
5aea7eb860 | ||
|
|
ec30df2020 | ||
|
|
bb33427c79 | ||
|
|
28a16cebda | ||
|
|
49c79405bc | ||
|
|
3098f32a07 | ||
|
|
b1e9c05bee | ||
|
|
69e06d89ff | ||
|
|
56b04017e7 | ||
|
|
3af61c031d | ||
|
|
f42a57088f | ||
|
|
4834452875 | ||
|
|
c5b9d99b48 | ||
|
|
f8d4c36f6d | ||
|
|
fa9ecbdb81 | ||
|
|
2bf6b29b8f | ||
|
|
25812f88f6 | ||
|
|
037989b8e4 | ||
|
|
dbc82cfb6a | ||
|
|
941a766aa3 | ||
|
|
72be7ad5f0 | ||
|
|
b2a36f71a0 | ||
|
|
6b17620389 | ||
|
|
b04195041a | ||
|
|
8ca4c66e3c | ||
|
|
449b7bf6e4 | ||
|
|
88e4b6390c | ||
|
|
de92bd1884 | ||
|
|
1b276a74fe | ||
|
|
fff31558a0 | ||
|
|
8084c4b2a3 | ||
|
|
1ca852191f | ||
|
|
af5fc6547a | ||
|
|
70f2b26c86 | ||
|
|
cfd95dbe87 | ||
|
|
c5bb404d6a | ||
|
|
4c23964964 | ||
|
|
e4a6dcd35c | ||
|
|
d4addd53ad | ||
|
|
d21298c156 | ||
|
|
9dba9fb366 | ||
|
|
09d40679c0 | ||
|
|
a323b126e5 | ||
|
|
553aad6ed2 | ||
|
|
5ca2ad6148 | ||
|
|
40537e1522 | ||
|
|
064a75b21b | ||
|
|
1d3445bc0f | ||
|
|
79232d02c9 | ||
|
|
9bd4986781 | ||
|
|
c3d443aaff | ||
|
|
b087888f94 | ||
|
|
da3dfd0998 | ||
|
|
4468d81472 | ||
|
|
7ddae8f2eb | ||
|
|
6b2851a671 | ||
|
|
4763969c8f | ||
|
|
f9b75e486c | ||
|
|
f868052062 | ||
|
|
61f0cbe10a | ||
|
|
0f4968d75c | ||
|
|
3077c22e4f | ||
|
|
0decc37b5a | ||
|
|
4a953b66e0 | ||
|
|
8435eeed4d | ||
|
|
cffb4de83b | ||
|
|
55175087c4 | ||
|
|
0ddfa8ad10 | ||
|
|
b74fb3f179 | ||
|
|
9d3d33b6a2 | ||
|
|
2abaa60c2e | ||
|
|
d5547f5c7c | ||
|
|
061510098c | ||
|
|
4fc3546887 | ||
|
|
868948509a | ||
|
|
e71492a2b3 | ||
|
|
c2055f3514 | ||
|
|
2809579dd7 | ||
|
|
c7afe3e9a4 | ||
|
|
cd026cd865 | ||
|
|
bc705aac03 | ||
|
|
a7c73036f0 | ||
|
|
e80d27f273 | ||
|
|
23adbf9540 | ||
|
|
a7347238e6 | ||
|
|
bf55666492 | ||
|
|
8ab0b0e460 | ||
|
|
b8e1849cec | ||
|
|
2255d05664 | ||
|
|
45a8eda49b | ||
|
|
b1207949ac | ||
|
|
d61fd01d61 | ||
|
|
4d5d3108fb | ||
|
|
e422f4154f | ||
|
|
0651f1bcd4 | ||
|
|
11f0ade921 | ||
|
|
5cab2e1c43 | ||
|
|
6381bdbf33 | ||
|
|
c8bcd4af2d | ||
|
|
cabb06230c | ||
|
|
4a75566a3b | ||
|
|
d9c924b472 | ||
|
|
52aa52c3b1 | ||
|
|
d254d6075a | ||
|
|
8004080643 | ||
|
|
13878974a6 | ||
|
|
6689e00e6a | ||
|
|
9b8a108f86 | ||
|
|
a3569d88c9 | ||
|
|
f2f6b6ede9 | ||
|
|
7f81cfd45a | ||
|
|
13b8e1a2ae | ||
|
|
36dbdf955d | ||
|
|
714b6c98ef | ||
|
|
7181d7ae6a | ||
|
|
9422d57283 | ||
|
|
5724cec1e5 | ||
|
|
35ca54d98f | ||
|
|
7398a9ebf9 | ||
|
|
4188fb536e | ||
|
|
a11e5e2deb | ||
|
|
5dd7e8c4d9 | ||
|
|
40bc390c3b | ||
|
|
8776348a80 | ||
|
|
49fb4421dd | ||
|
|
d232f08933 | ||
|
|
feba4da0b8 | ||
|
|
928d7186b5 | ||
|
|
3149a95d6a | ||
|
|
ed7ebfd58d | ||
|
|
808e310799 | ||
|
|
23fbb3cf22 | ||
|
|
c11e643f13 | ||
|
|
f5541860bc | ||
|
|
83ff0055b6 | ||
|
|
213f23aaf6 | ||
|
|
9970f3786f | ||
|
|
d01a568b8b | ||
|
|
e397884e1e | ||
|
|
ef65bac79b | ||
|
|
c0837c726f | ||
|
|
ce5429aba7 | ||
|
|
aa191e9202 | ||
|
|
a8f0283e93 | ||
|
|
999e47a26c | ||
|
|
a8103ca22d | ||
|
|
ef17f4913b | ||
|
|
1a30043776 | ||
|
|
b7e8b91eec | ||
|
|
3be1904653 | ||
|
|
cadd0e4244 | ||
|
|
f35ea9a3ca | ||
|
|
0971630e01 | ||
|
|
b60a9fa371 | ||
|
|
ab45360808 | ||
|
|
8523c0da32 | ||
|
|
f0dfa4d53d | ||
|
|
f2bedddce4 | ||
|
|
552138e851 | ||
|
|
ff71379a8e | ||
|
|
23a7feeb6e | ||
|
|
34f5db9ed4 | ||
|
|
9fd70cbdf9 | ||
|
|
87506852d1 | ||
|
|
e6893bc419 | ||
|
|
ebeab06710 | ||
|
|
1911c3690d | ||
|
|
3f3254a4df | ||
|
|
20ccb7b558 | ||
|
|
8cfe89604a | ||
|
|
15f0ba839f | ||
|
|
c400b914e5 | ||
|
|
a431c829cb | ||
|
|
25d0e125e5 | ||
|
|
b89a78ce17 | ||
|
|
f568012b9d | ||
|
|
328fb70e54 | ||
|
|
2f24e5ceb7 | ||
|
|
97809277df | ||
|
|
3d3e7a330c | ||
|
|
adf2275018 | ||
|
|
c1ecfbfe63 | ||
|
|
a7e7680789 | ||
|
|
382c19024f | ||
|
|
9379487942 | ||
|
|
5e99baf7b9 | ||
|
|
31951dae4c | ||
|
|
b1ab7f46e0 | ||
|
|
4e0c7ed5a6 | ||
|
|
2ef76d5e31 | ||
|
|
d3dda443cd | ||
|
|
ec3802c180 | ||
|
|
76654c7856 | ||
|
|
90239bb969 | ||
|
|
a6e4b0fea5 | ||
|
|
8ad37af70e | ||
|
|
c102d359f8 | ||
|
|
a07891e3e6 | ||
|
|
e946a35b18 | ||
|
|
68d7337f98 | ||
|
|
8b4198fd8d | ||
|
|
9c795fa40d | ||
|
|
5f2217a079 | ||
|
|
0cda4b7f23 | ||
|
|
e17e69604c | ||
|
|
e1bf4d4344 | ||
|
|
0c8a32b9ae | ||
|
|
d8c60aaae7 | ||
|
|
3216d65353 | ||
|
|
0df8d0a4e2 | ||
|
|
43f19034b9 | ||
|
|
2e6a937240 | ||
|
|
05d8a7f6be | ||
|
|
ceaf4bc6bc | ||
|
|
f2cc2f433c | ||
|
|
858aa6255c | ||
|
|
1d8ea9e869 | ||
|
|
8ead0b5483 | ||
|
|
72c081cfd6 | ||
|
|
1f701c94a7 | ||
|
|
acfc49fd41 | ||
|
|
9c29bd627e | ||
|
|
d24b141d8b | ||
|
|
bac9e005ae | ||
|
|
60bcca54eb | ||
|
|
eccea8a911 | ||
|
|
0833d0d8d5 | ||
|
|
55fce489bc | ||
|
|
2ce40c3c07 | ||
|
|
255cfb7d62 | ||
|
|
8a327be400 | ||
|
|
1cae76b443 | ||
|
|
828e8d2ae4 | ||
|
|
ce35509a40 | ||
|
|
24b8b4e904 | ||
|
|
c2c1dc7469 | ||
|
|
47c1071bb8 | ||
|
|
e401651f09 | ||
|
|
1449def040 | ||
|
|
d4d1ec2568 | ||
|
|
7455ac9bfb | ||
|
|
b6b1dcb275 | ||
|
|
2e4f49a223 | ||
|
|
88d4108f92 | ||
|
|
c9f3c02cb7 | ||
|
|
557372b312 | ||
|
|
18b24535fe | ||
|
|
20e0bca71d | ||
|
|
6977f655e3 | ||
|
|
e6fc9dc75d | ||
|
|
b57b3f4588 | ||
|
|
776ae92416 | ||
|
|
6ba53c1ac0 | ||
|
|
699d419c71 | ||
|
|
d4870b3854 | ||
|
|
e49a9096a5 | ||
|
|
33148ba832 | ||
|
|
bca23dd896 | ||
|
|
3a483a1b20 | ||
|
|
310d33b8ee | ||
|
|
8b5dcc3872 | ||
|
|
36d9af10f0 | ||
|
|
0c8fcbc684 | ||
|
|
7edab27e53 | ||
|
|
9b3531f634 | ||
|
|
d8f85a8981 | ||
|
|
3b229489c2 | ||
|
|
c2fcbbb0c6 | ||
|
|
8e82bf69d8 | ||
|
|
284f9e3f2f | ||
|
|
5ffc3561ed | ||
|
|
952f1271b4 | ||
|
|
250b445eee | ||
|
|
331472b592 | ||
|
|
82d5afe996 | ||
|
|
7361d5d3ea | ||
|
|
6086614274 | ||
|
|
6bb4780d32 | ||
|
|
631f5b4848 | ||
|
|
0f17712f6c | ||
|
|
4941e0f8ad | ||
|
|
fbee18e24d | ||
|
|
f37b2bc7c1 | ||
|
|
56278c6394 | ||
|
|
b1d6c03190 | ||
|
|
1200a77b22 | ||
|
|
bb9a18ef08 | ||
|
|
a8b493cb7d | ||
|
|
1a275ba184 | ||
|
|
187848660c | ||
|
|
c3f391dc5a | ||
|
|
971e6f2664 | ||
|
|
a1d6ef04ec | ||
|
|
ff47ab12fb | ||
|
|
a97e361661 | ||
|
|
34d84522dd | ||
|
|
3390fbf238 | ||
|
|
98ad1feaeb | ||
|
|
37e8a91d5b | ||
|
|
68c27eb2a1 | ||
|
|
143e75d213 | ||
|
|
295ac49f83 | ||
|
|
d31a498e6c | ||
|
|
2fd88a1c6a | ||
|
|
fbab930cb1 | ||
|
|
bfcbd72e4b | ||
|
|
d9d3caec22 | ||
|
|
238a56cac3 | ||
|
|
51765b1f65 | ||
|
|
7159ecb632 | ||
|
|
11f3425876 | ||
|
|
e131395cce | ||
|
|
d26ea2b948 | ||
|
|
5584a9ce5d | ||
|
|
e2e8b733a8 | ||
|
|
f18bf35b20 | ||
|
|
44d8cb77e3 | ||
|
|
fc10e3fcac | ||
|
|
b92ccb2de4 | ||
|
|
30af6e73be | ||
|
|
2895b9bfb7 | ||
|
|
84bd86f1ee | ||
|
|
7193f40b87 | ||
|
|
acd69fa4b0 | ||
|
|
71d8f5f96f | ||
|
|
856a2096eb | ||
|
|
76cb129d3c | ||
|
|
246d5cd587 | ||
|
|
f390671018 | ||
|
|
512ec7fb87 | ||
|
|
24219422df | ||
|
|
aed20cf7c6 | ||
|
|
6584933e92 | ||
|
|
8cf8da4c78 | ||
|
|
ad1f210528 | ||
|
|
cadab61a21 | ||
|
|
0b87f489d5 | ||
|
|
e3e5e016d5 | ||
|
|
3425b9a82e | ||
|
|
5ecfc58e5f | ||
|
|
6011dd7372 | ||
|
|
7ed45d26c2 | ||
|
|
fcdc85eab8 | ||
|
|
56a2924a33 | ||
|
|
09886a3f11 | ||
|
|
e8ec0dc701 | ||
|
|
41d9d57c84 | ||
|
|
b87bcc8f5f | ||
|
|
0541d8f1c5 | ||
|
|
4606693e62 | ||
|
|
e61d8e4fb8 | ||
|
|
6b4685b333 | ||
|
|
d4ac818a0b | ||
|
|
c17d95bfed | ||
|
|
f14184df30 | ||
|
|
47bbea9ba7 | ||
|
|
7265935cd4 | ||
|
|
40bda4b3d1 | ||
|
|
b7891f92a5 | ||
|
|
8b79017d0f | ||
|
|
5465ac9ba0 | ||
|
|
b8eaa9a527 | ||
|
|
5d274008db | ||
|
|
220e755596 | ||
|
|
fc5034696d | ||
|
|
4a6f77bc59 | ||
|
|
1e87850952 | ||
|
|
3472241289 | ||
|
|
a944b6ff79 | ||
|
|
6c4741bc61 | ||
|
|
8a42ef431b | ||
|
|
2cf1f0e8fc | ||
|
|
55e50eced6 | ||
|
|
30a2923380 | ||
|
|
f2b3752f3d | ||
|
|
36945a67d0 | ||
|
|
c5a2ca5c98 | ||
|
|
9f2ce0e296 | ||
|
|
55e10d8287 | ||
|
|
94c772e1a8 | ||
|
|
2b6d9c34c9 | ||
|
|
1a5c86d32e | ||
|
|
c7219fbdff | ||
|
|
4c249a1186 | ||
|
|
158ea1d43b | ||
|
|
535b8458d4 | ||
|
|
49b3f82675 | ||
|
|
9543203610 | ||
|
|
cacfe4d387 | ||
|
|
a7f0137e5f | ||
|
|
b2eb364a4b | ||
|
|
bb3b1bc6ba | ||
|
|
ae8eb3f177 | ||
|
|
27c7325174 | ||
|
|
8ee3d810b0 | ||
|
|
d7dde06552 | ||
|
|
448495a4a3 | ||
|
|
52cc8e2fcf | ||
|
|
fb9cdea008 | ||
|
|
6c54bf036c | ||
|
|
657bc4edcd | ||
|
|
b75dd5ff73 | ||
|
|
607664c860 | ||
|
|
094bd49f35 | ||
|
|
18fbe60381 | ||
|
|
f1956119fb | ||
|
|
876170767c | ||
|
|
f4f77ec88b | ||
|
|
9ba2038702 | ||
|
|
b176ba9e80 | ||
|
|
cacb47ca7e | ||
|
|
500e424fee | ||
|
|
f1b02c0cab | ||
|
|
828302702b | ||
|
|
0827d4fe40 | ||
|
|
ebff965414 | ||
|
|
b45954c560 | ||
|
|
80307a3bcd | ||
|
|
e8acb5967b | ||
|
|
939806f021 | ||
|
|
cc47bf8f6c | ||
|
|
8b80aaebf5 | ||
|
|
8f35ebc0c2 | ||
|
|
793bdd9743 | ||
|
|
9d50f52bb2 | ||
|
|
db62afbb64 | ||
|
|
3dc3e8e40e | ||
|
|
c79fc81292 | ||
|
|
62a6a878d4 | ||
|
|
4efb533d2e | ||
|
|
891473c7fc | ||
|
|
81e8ef5c40 | ||
|
|
e17885088b | ||
|
|
494340fe67 | ||
|
|
01625dfd49 | ||
|
|
a154f1540f | ||
|
|
5254fc6efe | ||
|
|
afa2e9c2f7 | ||
|
|
a4c8f1a0a4 | ||
|
|
d5a9a9a2d8 | ||
|
|
3b8f8fb0ef | ||
|
|
677033afca | ||
|
|
8e0d76b63b | ||
|
|
64df41ed90 | ||
|
|
442a372142 | ||
|
|
95e5baa967 | ||
|
|
b80edfb996 | ||
|
|
e06543bd17 | ||
|
|
cca8412921 | ||
|
|
d15a5ad5c1 | ||
|
|
8ed75dd176 | ||
|
|
d43ad263ea | ||
|
|
e602008459 | ||
|
|
322a18f0e6 | ||
|
|
05eb749e66 | ||
|
|
7e8d31a62c | ||
|
|
8ca0582afc | ||
|
|
b9f5fca546 | ||
|
|
5c2dcb5e74 | ||
|
|
3ef4af9326 | ||
|
|
f89f7ecd3e | ||
|
|
be0c457445 | ||
|
|
3c04dbb4ed | ||
|
|
cfca367eef | ||
|
|
8a243c5872 | ||
|
|
b30b3f3aeb | ||
|
|
2d3906450a | ||
|
|
5ecc46d85b | ||
|
|
ddd6f3dbe5 | ||
|
|
f5237db580 | ||
|
|
761fd13a70 | ||
|
|
e3fa06d7ff | ||
|
|
61a76f4493 | ||
|
|
c5f46702c8 | ||
|
|
c24e5cd3f6 | ||
|
|
cc3035267f | ||
|
|
29ee8250e9 | ||
|
|
47ed0b7627 | ||
|
|
423280cee1 | ||
|
|
8c0faa0b9a | ||
|
|
45ab2a3d7a | ||
|
|
8804f5c423 | ||
|
|
1078aa499c | ||
|
|
05d015169c | ||
|
|
6c9e7586d5 | ||
|
|
28bed0041e | ||
|
|
6f03e30151 | ||
|
|
6085d6ffd1 | ||
|
|
6ecd93d0c9 | ||
|
|
863ea7294f | ||
|
|
af59824819 | ||
|
|
80e17ab721 | ||
|
|
f89d69b081 | ||
|
|
5ba413569e | ||
|
|
b3e969f000 | ||
|
|
a9a40ca46c | ||
|
|
79aada0b87 | ||
|
|
162a7b56fe | ||
|
|
69dc22c10f | ||
|
|
9642cda949 | ||
|
|
dd6a9a0b84 | ||
|
|
945dcc6c2b | ||
|
|
f60791ac7c | ||
|
|
b64155a165 | ||
|
|
472f7725c7 | ||
|
|
90f01b5fc4 | ||
|
|
20a2daa114 | ||
|
|
9b6a2c7068 | ||
|
|
0a4d3ef6e6 | ||
|
|
2dc1851892 | ||
|
|
8d721d086c | ||
|
|
6f0bb30def | ||
|
|
c54f04ef4c | ||
|
|
eb83081a5c | ||
|
|
8976930e20 | ||
|
|
164a81776e | ||
|
|
9c8526db49 | ||
|
|
d92f9b4dbd | ||
|
|
1556163fb0 | ||
|
|
616962200a | ||
|
|
eb9c44a347 | ||
|
|
f36ac48de0 | ||
|
|
f63267a7f9 | ||
|
|
2c8dcd86e5 | ||
|
|
9631519eb1 | ||
|
|
557d076d2e | ||
|
|
8a40c91d1a | ||
|
|
90efa3b610 | ||
|
|
35dc4800e0 | ||
|
|
ec4e4d3b72 | ||
|
|
63312ac4b8 | ||
|
|
d158a7d51e | ||
|
|
209a2ab3ec | ||
|
|
009fa2f1b7 | ||
|
|
5221767a70 | ||
|
|
9492ff26c6 | ||
|
|
06764d0f36 | ||
|
|
0db76aada0 | ||
|
|
7362416afb | ||
|
|
9be854031f | ||
|
|
709851503f | ||
|
|
6ca47dc3b3 | ||
|
|
d8774901ee | ||
|
|
8dba2a88e2 | ||
|
|
2c33c64fae | ||
|
|
b9ae01d819 | ||
|
|
2390b80359 | ||
|
|
c34c3eb016 | ||
|
|
85d159bdd1 | ||
|
|
da1d2b2c48 | ||
|
|
5f8b0b3c89 | ||
|
|
0f868f7649 | ||
|
|
8b0785996e | ||
|
|
645d8e0ebd | ||
|
|
3a3c0befa7 | ||
|
|
80c40e6050 | ||
|
|
31730e7197 | ||
|
|
7d76db00ac | ||
|
|
8aceb8bf53 | ||
|
|
a17d1be7a4 | ||
|
|
1e6cc63abe | ||
|
|
3b300a4d6a | ||
|
|
3e727c5e5d | ||
|
|
e0edac32c7 | ||
|
|
e4b3bc4209 | ||
|
|
51b09efceb | ||
|
|
2dabacd024 | ||
|
|
0613dcc87b | ||
|
|
d59a2a4cfc | ||
|
|
2c091f3a3c | ||
|
|
cfcdc53185 | ||
|
|
bd33018660 | ||
|
|
e7589945a2 | ||
|
|
67a5594909 | ||
|
|
70ad656af0 | ||
|
|
f22b83d379 | ||
|
|
114f84c948 | ||
|
|
7875df0d6b | ||
|
|
0d286b99d5 | ||
|
|
e03d4f2de8 | ||
|
|
7fddce4a1f | ||
|
|
3cd8b7d882 | ||
|
|
3578a3e311 | ||
|
|
a9ad8d67aa | ||
|
|
43e1121618 | ||
|
|
97dd1b4cf3 | ||
|
|
288635abc9 | ||
|
|
7884423e05 | ||
|
|
1615fa63e3 | ||
|
|
39ab1e1ea7 | ||
|
|
10c048d84a | ||
|
|
a458482e51 | ||
|
|
de46dbd56f | ||
|
|
60365ad36a | ||
|
|
466e6d9b30 | ||
|
|
11d48554e3 | ||
|
|
b9bcfe36ff | ||
|
|
05faa7bdf2 | ||
|
|
88b1f0ca7f | ||
|
|
f0f7bda2f3 | ||
|
|
664d0ea023 | ||
|
|
cd7c00ef8e | ||
|
|
3f20981aab | ||
|
|
f54a812ad5 | ||
|
|
aa1d67a4de | ||
|
|
feb2150d9b | ||
|
|
3aa525b0c0 | ||
|
|
6323d5afed | ||
|
|
e3e3b4da58 | ||
|
|
a0bd517380 | ||
|
|
4316b15ae2 | ||
|
|
ef1ce7d4d6 | ||
|
|
a643f40cce | ||
|
|
47099e2855 | ||
|
|
2deb2bf03f | ||
|
|
3bb05edb52 | ||
|
|
ee2169dd13 | ||
|
|
11282aaca3 | ||
|
|
909bc92c01 | ||
|
|
a6f9272d4b | ||
|
|
911596daf8 | ||
|
|
8d8482d60b | ||
|
|
f3cc8c71c4 | ||
|
|
f6b3c62b06 | ||
|
|
26afe04926 | ||
|
|
500a755250 | ||
|
|
d02bf258af | ||
|
|
56990618e9 | ||
|
|
54a85d3a63 | ||
|
|
d56beedd7a | ||
|
|
c2d3e99ddd | ||
|
|
5e48b3f7f7 | ||
|
|
00d62b3423 | ||
|
|
c957124fad | ||
|
|
28063aa7f7 | ||
|
|
c458e4a93b | ||
|
|
e7ae62ba76 | ||
|
|
ff5411a93a | ||
|
|
d3073e5e23 | ||
|
|
34ae4844fa | ||
|
|
8191ec01e5 | ||
|
|
4d39ab9753 | ||
|
|
7a1df15724 | ||
|
|
42b5574f9b | ||
|
|
5f4be0de35 | ||
|
|
6c605f55f9 | ||
|
|
774c6e8ac0 | ||
|
|
17be6b860e | ||
|
|
474ac4a15d | ||
|
|
b8fedf76cd | ||
|
|
ca88c59d4e | ||
|
|
d69e62589a | ||
|
|
c9d4995900 | ||
|
|
279e809aaf | ||
|
|
d61857efae | ||
|
|
0d037e96fb | ||
|
|
6376f9aef4 | ||
|
|
f5a1fa21f7 | ||
|
|
4a90dac68e | ||
|
|
2624e56de5 | ||
|
|
aef54d6694 | ||
|
|
e839a7784c | ||
|
|
bea99abd8d | ||
|
|
a5c4ae955a | ||
|
|
d7d53849a3 | ||
|
|
b354f722be | ||
|
|
ea1aad9774 | ||
|
|
817d644795 | ||
|
|
56b8c4bfdb | ||
|
|
c65c26b463 | ||
|
|
bf059e5ee8 | ||
|
|
15a5f425bf | ||
|
|
3125d24ded | ||
|
|
6b6d105c2f | ||
|
|
bab44c52ae | ||
|
|
2f19605750 | ||
|
|
7311db3a63 | ||
|
|
0a00936e99 | ||
|
|
7cac207c00 | ||
|
|
feb412b02a | ||
|
|
199de9ebc0 | ||
|
|
504ae0193f | ||
|
|
1ae403b742 | ||
|
|
939c99cdbf | ||
|
|
2f36acae49 | ||
|
|
e938132c53 | ||
|
|
1b34286264 | ||
|
|
54f4f6d2d7 | ||
|
|
07e5e8e67a | ||
|
|
3c25094495 | ||
|
|
95e3a5944d | ||
|
|
64f29120c8 | ||
|
|
d92434b1e9 | ||
|
|
01cd056bcc | ||
|
|
56f2ea3ec2 | ||
|
|
d45695a088 | ||
|
|
2ceeac41fe | ||
|
|
cc4ada99d8 | ||
|
|
16d67f55b3 | ||
|
|
18b41adbf6 | ||
|
|
898fdf7a60 | ||
|
|
78143c2ff4 | ||
|
|
7b1524ad01 | ||
|
|
5799485b0f | ||
|
|
9cddb6ca39 | ||
|
|
defc17ba46 | ||
|
|
106d5afba1 | ||
|
|
0a9965292c | ||
|
|
4fb66e632f | ||
|
|
5787895794 | ||
|
|
d90489b31d | ||
|
|
f38912a0c9 | ||
|
|
f24ab8508e | ||
|
|
2d8fff099f | ||
|
|
dce36d8ded | ||
|
|
18d0278279 | ||
|
|
4e525040f3 | ||
|
|
fdf2649f2f | ||
|
|
b09c660833 | ||
|
|
c02a24cf71 | ||
|
|
a77136bd1d | ||
|
|
e0eb5eb2b1 | ||
|
|
714fd93292 | ||
|
|
a293b5a371 | ||
|
|
1c93868ae1 | ||
|
|
61ff0452e1 | ||
|
|
406098e55a | ||
|
|
a2825be819 | ||
|
|
6830b08723 | ||
|
|
eead2f059b | ||
|
|
291c111ce8 | ||
|
|
2ccf063dfe | ||
|
|
49aee8b931 | ||
|
|
f2a3b557c8 | ||
|
|
b0eceddcec | ||
|
|
0a062d26e6 | ||
|
|
20b2dd6b19 | ||
|
|
83592a5e70 | ||
|
|
70fb733fea | ||
|
|
eb8333c772 | ||
|
|
c9a98b68c8 | ||
|
|
247d3ed729 | ||
|
|
031c6428d5 | ||
|
|
f2e9d585f7 | ||
|
|
8af9853b9a | ||
|
|
783f50657b | ||
|
|
3a50b91722 | ||
|
|
3631d1349e | ||
|
|
05c8687041 | ||
|
|
66f32b7601 | ||
|
|
9101916719 | ||
|
|
edb594461d | ||
|
|
9464b71a6e | ||
|
|
7d56e2a937 | ||
|
|
218aa03f05 | ||
|
|
1db03a10d7 | ||
|
|
e1f818ffb7 | ||
|
|
9934f505a5 | ||
|
|
8c2b8f7241 | ||
|
|
bf70c2c660 | ||
|
|
74b912a0b7 | ||
|
|
93d40b083e | ||
|
|
162ee28d0c | ||
|
|
d328d17d03 | ||
|
|
2778d88e8a | ||
|
|
b5c6178644 | ||
|
|
ea8927e1da | ||
|
|
bc1065a7fc | ||
|
|
f4c7d389e5 | ||
|
|
03387391de | ||
|
|
24df5f5208 | ||
|
|
9348a8ab15 | ||
|
|
fbd55dd740 | ||
|
|
e5e26413e9 | ||
|
|
527fe2f5e1 | ||
|
|
38d213ee6c | ||
|
|
613f2d3b86 | ||
|
|
e7ad972783 | ||
|
|
2f939d8c56 | ||
|
|
7ef751f96d | ||
|
|
fb66fb12c5 | ||
|
|
042dcf795c | ||
|
|
aad39c5ffc | ||
|
|
c3ed710e31 | ||
|
|
cb65907e60 | ||
|
|
bb8a263d70 | ||
|
|
70fd94edb3 | ||
|
|
d0492898eb | ||
|
|
c6ba03802f | ||
|
|
1bebcef265 | ||
|
|
209fbf82c4 | ||
|
|
6ce79ae1d0 | ||
|
|
b3eb5c4f0e | ||
|
|
ec4e9780ed | ||
|
|
22abbffbb7 | ||
|
|
05a724afae | ||
|
|
1957b002bc | ||
|
|
04cef25add | ||
|
|
ab1a6d8829 | ||
|
|
98afb0e998 | ||
|
|
e9d81fc883 | ||
|
|
22fac5e1e0 | ||
|
|
b6a2a4ad5a | ||
|
|
5f00347019 | ||
|
|
89a22ded54 | ||
|
|
1e31fa89aa | ||
|
|
b477b7f777 | ||
|
|
0de15f7a97 | ||
|
|
35ecf40259 | ||
|
|
009363a7bb | ||
|
|
a3758612ec | ||
|
|
8dc94e014f | ||
|
|
ad886ac164 | ||
|
|
78e7c8b8e9 | ||
|
|
3779085051 | ||
|
|
c29c4ceb0f | ||
|
|
07fc047dd8 | ||
|
|
bc46694ea7 | ||
|
|
0c2827e130 | ||
|
|
cb09e0bc9a | ||
|
|
06d5ea9d51 | ||
|
|
a4650c6226 | ||
|
|
c85a603491 | ||
|
|
536585b846 | ||
|
|
ecde222512 | ||
|
|
5b472ff67c | ||
|
|
6f2ec22894 | ||
|
|
05798fe07a | ||
|
|
8ab5ffd876 | ||
|
|
2b6709d83f | ||
|
|
e4cc5b3847 | ||
|
|
8bad56e897 | ||
|
|
92e691408f | ||
|
|
0a9c234127 | ||
|
|
0283a1ab74 | ||
|
|
b32096b16e | ||
|
|
3d7582faec | ||
|
|
54a88ab5ab | ||
|
|
aff5ff08d5 | ||
|
|
fc0440546f | ||
|
|
172b8d2427 | ||
|
|
6d10a498a5 | ||
|
|
881819ed5f | ||
|
|
3275c5f710 | ||
|
|
b0cc1a38c3 | ||
|
|
e8025dbc81 | ||
|
|
e10182c839 | ||
|
|
b4f1fe08f0 | ||
|
|
64171fa2a1 | ||
|
|
048eacd305 | ||
|
|
24aa72c19d | ||
|
|
92b5fe4be4 | ||
|
|
939055f19c | ||
|
|
c47f3e3307 | ||
|
|
cf6a1ac9ad | ||
|
|
f1146a3443 | ||
|
|
6823a62644 | ||
|
|
2516a1e298 | ||
|
|
288f93c5dd | ||
|
|
8ef64dbe74 | ||
|
|
01e091fd17 | ||
|
|
8b4c0b456b | ||
|
|
02a601deff | ||
|
|
b207fadc04 | ||
|
|
bf3883ed46 | ||
|
|
3a58e9d33a | ||
|
|
570c54002f | ||
|
|
d51c067e1b | ||
|
|
2fea5d428d | ||
|
|
2b8a8b03a8 | ||
|
|
d51e0c49b1 | ||
|
|
d913534793 | ||
|
|
36907edd50 | ||
|
|
7ec169ab10 | ||
|
|
7873da1ae5 | ||
|
|
ef5a6e7880 | ||
|
|
96f01e670f | ||
|
|
10139241f5 | ||
|
|
5902be2a49 | ||
|
|
cc946ce068 | ||
|
|
1102fdc44b | ||
|
|
c995c81fff | ||
|
|
6684af9938 | ||
|
|
8bafd12f95 | ||
|
|
76266cf31b | ||
|
|
4ad0cdf5d4 | ||
|
|
1a87d3a659 | ||
|
|
085f2c6ca0 | ||
|
|
98fdb95645 | ||
|
|
3035c9a366 | ||
|
|
5004cf331a | ||
|
|
74eb8c8622 | ||
|
|
b74300f67c | ||
|
|
107babe8f4 | ||
|
|
8fd9a22d18 | ||
|
|
8c5c1316dd | ||
|
|
daff5d8b5a | ||
|
|
6c4a7b626e | ||
|
|
1aa5943e67 | ||
|
|
69fe889f92 | ||
|
|
2ef87ad110 | ||
|
|
c655e6ea73 | ||
|
|
5d7ef9281f | ||
|
|
6fa00e7cc8 | ||
|
|
2f2825f15e | ||
|
|
e377fe5503 | ||
|
|
69b41dd72e | ||
|
|
69fa9874dd | ||
|
|
a620a5c430 | ||
|
|
1f3db8b602 | ||
|
|
f6732a484e | ||
|
|
4015122d33 | ||
|
|
42eb811910 | ||
|
|
c9042ffedd | ||
|
|
4e2c6a7b8e | ||
|
|
7453bf2ee6 | ||
|
|
7d17c652f3 | ||
|
|
075f00cecd | ||
|
|
b9f2ba0717 | ||
|
|
ed04be5faa | ||
|
|
90119c75d5 | ||
|
|
d30056026b | ||
|
|
bc8a5916d8 | ||
|
|
f202602f99 | ||
|
|
69f361a3a1 | ||
|
|
da9ff0cc66 | ||
|
|
703ff09a91 | ||
|
|
30035ce1c2 | ||
|
|
39b74ebfd4 | ||
|
|
3bd677c102 | ||
|
|
4eb7d2868c | ||
|
|
0e4473685b | ||
|
|
b721ed49ab | ||
|
|
25601b9fcc | ||
|
|
db10c8ab46 | ||
|
|
55f78e3b64 | ||
|
|
7abf349730 | ||
|
|
f9d41caeb6 | ||
|
|
b166410cbf | ||
|
|
31d5a7ae9e | ||
|
|
5bb91759b4 | ||
|
|
80c4b7c9bb | ||
|
|
ea0a9ceb37 | ||
|
|
68dd2a6b91 | ||
|
|
f875976268 | ||
|
|
e23c6899e0 | ||
|
|
c35c7b2cea | ||
|
|
1c2aa44d46 | ||
|
|
3b44a0da32 | ||
|
|
58353e2839 | ||
|
|
5e0572637e | ||
|
|
501b26decd | ||
|
|
c6596f2c54 | ||
|
|
2863308090 | ||
|
|
7fef1fdc83 | ||
|
|
3081c151bd | ||
|
|
c793295be0 | ||
|
|
fe0a35cc7a | ||
|
|
0b67eebaec | ||
|
|
03201e2f20 | ||
|
|
dfc32b26a6 | ||
|
|
173ad339bb | ||
|
|
89fd962615 | ||
|
|
a928cd3fa1 | ||
|
|
f190a6ebc5 | ||
|
|
9beb9fd941 | ||
|
|
525a1228c3 | ||
|
|
19fd25c7cd | ||
|
|
5b0927ca4b | ||
|
|
324d4433c3 | ||
|
|
615ca56ea3 | ||
|
|
41dd163453 | ||
|
|
5cd2c77d98 | ||
|
|
f270f7430c | ||
|
|
99b23627d0 | ||
|
|
26fcb1b2a0 | ||
|
|
e9c4e8123c | ||
|
|
a290e01bdf | ||
|
|
9cc392fa02 | ||
|
|
7c2046cce7 | ||
|
|
4d731ca30b | ||
|
|
f2016f26d7 | ||
|
|
b13171cc45 | ||
|
|
9c645e2010 | ||
|
|
bb6f409e89 | ||
|
|
61ec7723f6 | ||
|
|
9c136a5579 | ||
|
|
a5733508ae | ||
|
|
a8818c16d8 | ||
|
|
c8e1e6dc8a | ||
|
|
7bcea98d0c | ||
|
|
74b15d10d9 | ||
|
|
356c70cdae | ||
|
|
dfb5c37d98 | ||
|
|
30dcf6ff47 | ||
|
|
a0603ad3b7 | ||
|
|
551add5f44 | ||
|
|
88944a31ec | ||
|
|
3473ebc0fe | ||
|
|
8c657910ae | ||
|
|
1886c44579 | ||
|
|
1dcc1871fb | ||
|
|
19e688effb | ||
|
|
6a2b885988 | ||
|
|
bfc4775b34 | ||
|
|
981004606b | ||
|
|
9d40fd1eda | ||
|
|
db1e5f10ea | ||
|
|
fbb6b56d99 | ||
|
|
f1f70133dc | ||
|
|
d0f55e5125 | ||
|
|
5e308dbd51 | ||
|
|
c3c554f4d6 | ||
|
|
320c06e0a4 | ||
|
|
2e398c5da4 | ||
|
|
b1484104bd | ||
|
|
c738a9a044 | ||
|
|
519cb71022 | ||
|
|
fcd92d27f7 | ||
|
|
3eacfa9831 | ||
|
|
ff6df76e36 | ||
|
|
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 | ||
|
|
bb7a7d94ef | ||
|
|
9a475cc010 | ||
|
|
ae30c285a2 | ||
|
|
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 | ||
|
|
9fe531d1aa | ||
|
|
9892d06c0d | ||
|
|
d1e475da89 | ||
|
|
c45dc277b6 | ||
|
|
29ae57465b | ||
|
|
f899aaad44 | ||
|
|
7bbe56d61c | ||
|
|
8ad69cea33 | ||
|
|
11e1859f7d | ||
|
|
23856d65e2 | ||
|
|
bc0a8e7733 | ||
|
|
2164e13303 | ||
|
|
3f4567d088 | ||
|
|
bf4ef2b314 | ||
|
|
b011fe28d9 | ||
|
|
b318d5350c | ||
|
|
21ee63b7fb | ||
|
|
4057a076a2 | ||
|
|
6e13134328 | ||
|
|
29ae66c6db | ||
|
|
464003d674 | ||
|
|
03bbef07b5 | ||
|
|
ecb514dd0a | ||
|
|
04f6c478cc | ||
|
|
20399b8262 | ||
|
|
e2b518568e | ||
|
|
100cbd4032 | ||
|
|
673113cb98 | ||
|
|
a5d29a1048 | ||
|
|
4f1bb12d36 | ||
|
|
3d22e3bb7d | ||
|
|
af909e0ee6 | ||
|
|
fe46afd08d | ||
|
|
a1e609d005 | ||
|
|
668d14e32d | ||
|
|
f02c37ec07 | ||
|
|
4e50a03dfc | ||
|
|
a3a244c4af | ||
|
|
d0e9e90ebe | ||
|
|
1578a28363 | ||
|
|
9c13d2d88b | ||
|
|
b005da395f | ||
|
|
1b47a42792 | ||
|
|
d477021532 | ||
|
|
b895235ec1 | ||
|
|
3a01b370d3 | ||
|
|
689426180a | ||
|
|
d0d165ad16 | ||
|
|
0cb20fc080 | ||
|
|
dee3df4e11 | ||
|
|
814873c643 | ||
|
|
0936e394d4 | ||
|
|
ad91eb44fb | ||
|
|
76c217d9cc | ||
|
|
46b4000e75 | ||
|
|
8ac8aa72ce | ||
|
|
8df376860c | ||
|
|
eec0a31216 | ||
|
|
fb3fde3d19 | ||
|
|
1482b9563c | ||
|
|
6d989f9160 | ||
|
|
f37990351e | ||
|
|
a44591ca6b | ||
|
|
37f255d761 | ||
|
|
72cf5c91a5 | ||
|
|
dfe1b126c4 | ||
|
|
4229a3e5e9 | ||
|
|
7a3add3a2e | ||
|
|
3992c0fba8 | ||
|
|
763aa6aa5c | ||
|
|
ce0ca3cc61 | ||
|
|
5495f23e4e | ||
|
|
e9bd7b1d47 | ||
|
|
a7d1b0b42c | ||
|
|
e1b8419a07 | ||
|
|
932d410b66 | ||
|
|
c297a86211 | ||
|
|
1b65193fe4 | ||
|
|
a06098bb16 | ||
|
|
a675dc3f2c | ||
|
|
15b9fb68d7 | ||
|
|
642c31c361 | ||
|
|
8e21488542 | ||
|
|
deb6e76e08 | ||
|
|
23eece9443 | ||
|
|
1b51b9ade3 | ||
|
|
a36352dfb6 | ||
|
|
271163ed66 | ||
|
|
3290dbbe48 | ||
|
|
d9aa19d2cd | ||
|
|
58e4fbd0fb | ||
|
|
ec7bbd4ca8 | ||
|
|
2f9e650739 | ||
|
|
4ad2b68ee1 | ||
|
|
7a0b92d2c1 | ||
|
|
cfc4697236 | ||
|
|
bc3ece778d | ||
|
|
6d0c67af9a | ||
|
|
deb48c124f | ||
|
|
ca9ca36315 | ||
|
|
ced96905e9 | ||
|
|
d5ffec64f2 | ||
|
|
17904b3106 | ||
|
|
7b16a42f31 | ||
|
|
28dd956449 | ||
|
|
bf397db73e | ||
|
|
963eacfe05 | ||
|
|
ee40bc0423 | ||
|
|
428d5e9a06 | ||
|
|
88e6ce041d | ||
|
|
e3c0fdfeb7 | ||
|
|
dfbf1a952f | ||
|
|
8f3bbadf73 | ||
|
|
6976532ef5 | ||
|
|
89e63c7e90 | ||
|
|
06e89614e9 | ||
|
|
d859d925e3 | ||
|
|
d52fdde2f8 | ||
|
|
533f707578 | ||
|
|
4ea397bc71 | ||
|
|
7b49677d24 | ||
|
|
56d4b7b0f7 | ||
|
|
96bc557e21 | ||
|
|
11fcfc4bf5 | ||
|
|
2ca9b6b005 | ||
|
|
885069d440 | ||
|
|
6fc798ebe4 | ||
|
|
2b4500363b | ||
|
|
2d91a7a3c4 | ||
|
|
d15a085dd0 | ||
|
|
8718321727 | ||
|
|
d44e48114e | ||
|
|
cfac2be334 | ||
|
|
4a4db7ab56 | ||
|
|
23713d82a0 | ||
|
|
e19a6c3624 | ||
|
|
2792238472 | ||
|
|
fa77b7b69d | ||
|
|
d68c262b96 | ||
|
|
98c94912e1 | ||
|
|
a26377d229 | ||
|
|
e464c04490 | ||
|
|
bb7db11214 | ||
|
|
1f29d01694 | ||
|
|
d6d192cb0a | ||
|
|
0ec6eab683 | ||
|
|
159b29b80b | ||
|
|
942bdd2b35 |
38
.editorconfig
Normal file
38
.editorconfig
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# EditorConfig is awesome: https://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 = 4
|
||||||
|
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
|
||||||
2
.github/dco.yml
vendored
Normal file
2
.github/dco.yml
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
require:
|
||||||
|
members: false
|
||||||
10
.github/dependabot.yml
vendored
Normal file
10
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: github-actions
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
||||||
|
day: saturday
|
||||||
|
time: "10:00"
|
||||||
|
open-pull-requests-limit: 10
|
||||||
|
target-branch: developement
|
||||||
40
.github/workflows/codeql-analysis.yml
vendored
Normal file
40
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- development
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- development
|
||||||
|
schedule:
|
||||||
|
- cron: '32 11 * * 6'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
-
|
||||||
|
name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v1
|
||||||
|
with:
|
||||||
|
languages: 'python'
|
||||||
|
-
|
||||||
|
name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v1
|
||||||
|
-
|
||||||
|
name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v1
|
||||||
24
.github/workflows/stale.yml
vendored
Normal file
24
.github/workflows/stale.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
name: Mark stale issues
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '30 * * * *'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
stale:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/stale@v4
|
||||||
|
with:
|
||||||
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
debug-only: true
|
||||||
|
days-before-stale: 30
|
||||||
|
days-before-close: 5
|
||||||
|
stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Please comment or update this issue or it will be closed in 5 days.'
|
||||||
|
stale-issue-label: 'Submitter Attention Required'
|
||||||
|
exempt-issue-labels: 'pinned, Fixed in next release, Bug: Confirmed'
|
||||||
|
exempt-all-issue-assignees: true
|
||||||
48
.github/workflows/test.yml
vendored
Normal file
48
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
name: Test Supported Distributions
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened, ready_for_review]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
smoke-test:
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
-
|
||||||
|
name: Run Smoke Tests
|
||||||
|
run: |
|
||||||
|
# Ensure scripts in repository are executable
|
||||||
|
IFS=$'\n';
|
||||||
|
for f in $(find . -name '*.sh'); do if [[ ! -x $f ]]; then echo "$f is not executable" && FAIL=1; fi ;done
|
||||||
|
unset IFS;
|
||||||
|
# If FAIL is 1 then we fail.
|
||||||
|
[[ $FAIL == 1 ]] && exit 1 || echo "Smoke Tests Passed"
|
||||||
|
|
||||||
|
distro-test:
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: smoke-test
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
distro: [debian_9, debian_10, debian_11, ubuntu_16, ubuntu_18, ubuntu_20, ubuntu_21, centos_7, centos_8, fedora_33, fedora_34]
|
||||||
|
env:
|
||||||
|
DISTRO: ${{matrix.distro}}
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
-
|
||||||
|
name: Set up Python 3.8
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: 3.8
|
||||||
|
-
|
||||||
|
name: Install dependencies
|
||||||
|
run: pip install -r test/requirements.txt
|
||||||
|
-
|
||||||
|
name: Test with tox
|
||||||
|
run: tox -c test/tox.${DISTRO}.ini
|
||||||
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
.DS_Store
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
__pycache__
|
||||||
|
.cache
|
||||||
|
.pytest_cache
|
||||||
|
.tox
|
||||||
|
.eggs
|
||||||
|
*.egg-info
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
.vscode/
|
||||||
6
.stickler.yml
Normal file
6
.stickler.yml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
linters:
|
||||||
|
shellcheck:
|
||||||
|
shell: bash
|
||||||
|
phpcs:
|
||||||
|
flake8:
|
||||||
|
max-line-length: 120
|
||||||
7
CONTRIBUTING.md
Normal file
7
CONTRIBUTING.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Contributors Guide
|
||||||
|
|
||||||
|
Please read and understand the contribution guide before creating an issue or pull request.
|
||||||
|
|
||||||
|
The guide can be found here: [https://docs.pi-hole.net/guides/github/contributing/](https://docs.pi-hole.net/guides/github/contributing/)
|
||||||
|
|
||||||
|
|
||||||
389
LICENSE
389
LICENSE
@@ -1,339 +1,146 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
Copyright (C) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||||
Version 2, June 1991
|
Pi-hole Core
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
|
This software is licensed under the European Union Public License (EUPL)
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
The license is available in the 22 official languages of the EU. The English version is included here.
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Please see https://joinup.ec.europa.eu/community/eupl/og_page/eupl for official translations of the other languages.
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
This license applies to the whole project EXCEPT:
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
- any commits made to the master branch prior to the release of version 3.0
|
||||||
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.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
The licenses that existed prior to this change have remained intact.
|
||||||
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.
|
|
||||||
|
|
||||||
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.
|
EUROPEAN UNION PUBLIC LICENCE v. 1.2
|
||||||
These restrictions translate to certain responsibilities for you if you
|
|
||||||
distribute copies of the software, or if you modify it.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
EUPL © the European Union 2007, 2016
|
||||||
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.
|
|
||||||
|
|
||||||
We protect your rights with two steps: (1) copyright the software, and
|
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).
|
||||||
(2) offer you this license which gives you legal permission to copy,
|
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:
|
||||||
distribute and/or modify the software.
|
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
|
1. Definitions
|
||||||
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.
|
|
||||||
|
|
||||||
Finally, any free program is threatened constantly by software
|
In this Licence, the following terms have the following meaning:
|
||||||
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.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
- The Licence: this Licence.
|
||||||
modification follow.
|
- 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
|
2. Scope of the rights granted by the Licence
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
||||||
|
|
||||||
0. This License applies to any program or other work which contains
|
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:
|
||||||
a notice placed by the copyright holder saying it may be distributed
|
- use the Work in any circumstance and for all usage,
|
||||||
under the terms of this General Public License. The "Program", below,
|
- reproduce the Work,
|
||||||
refers to any such program or work, and a "work based on the Program"
|
- modify the Work, and make Derivative Works based upon the Work,
|
||||||
means either the Program or any derivative work under copyright law:
|
- 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,
|
||||||
that is to say, a work containing the Program or a portion of it,
|
- distribute the Work or copies thereof,
|
||||||
either verbatim or with modifications and/or translated into another
|
- lend and rent the Work or copies thereof,
|
||||||
language. (Hereinafter, translation is included without limitation in
|
- sublicense rights in the Work or copies thereof.
|
||||||
the term "modification".) Each licensee is addressed as "you".
|
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
|
3. Communication of the Source Code
|
||||||
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.
|
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Program's
|
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.
|
||||||
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.
|
|
||||||
|
|
||||||
You may charge a fee for the physical act of transferring a copy, and
|
4. Limitations on copyright
|
||||||
you may at your option offer warranty protection in exchange for a fee.
|
|
||||||
|
|
||||||
2. You may modify your copy or copies of the Program or any portion
|
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.
|
||||||
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:
|
|
||||||
|
|
||||||
a) You must cause the modified files to carry prominent notices
|
5. Obligations of the Licensee
|
||||||
stating that you changed the files and the date of any change.
|
|
||||||
|
|
||||||
b) You must cause any work that you distribute or publish, that in
|
The grant of the rights mentioned above is subject to some restrictions and obligations imposed on the Licensee. Those obligations are the following:
|
||||||
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.
|
|
||||||
|
|
||||||
c) If the modified program normally reads commands interactively
|
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.
|
||||||
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.)
|
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
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.
|
||||||
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.
|
|
||||||
|
|
||||||
Thus, it is not the intent of this section to claim rights or contest
|
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.
|
||||||
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.
|
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Program
|
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.
|
||||||
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.
|
|
||||||
|
|
||||||
3. You may copy and distribute the Program (or a work based on it,
|
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.
|
||||||
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:
|
|
||||||
|
|
||||||
a) Accompany it with the complete corresponding machine-readable
|
6. Chain of Authorship
|
||||||
source code, which must be distributed under the terms of Sections
|
|
||||||
1 and 2 above on a medium customarily used for software interchange; or,
|
|
||||||
|
|
||||||
b) Accompany it with a written offer, valid for at least three
|
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.
|
||||||
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,
|
|
||||||
|
|
||||||
c) Accompany it with the information you received as to the offer
|
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.
|
||||||
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.)
|
|
||||||
|
|
||||||
The source code for a work means the preferred form of the work for
|
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.
|
||||||
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.
|
|
||||||
|
|
||||||
If distribution of executable or object code is made by offering
|
7. Disclaimer of Warranty
|
||||||
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.
|
|
||||||
|
|
||||||
4. You may not copy, modify, sublicense, or distribute the Program
|
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.
|
||||||
except as expressly provided under this License. Any attempt
|
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.
|
||||||
otherwise to copy, modify, sublicense or distribute the Program is
|
This disclaimer of warranty is an essential part of the Licence and a condition for the grant of any rights to the Work.
|
||||||
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.
|
|
||||||
|
|
||||||
5. You are not required to accept this License, since you have not
|
8. Disclaimer of Liability
|
||||||
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.
|
|
||||||
|
|
||||||
6. Each time you redistribute the Program (or any work based on the
|
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.
|
||||||
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.
|
|
||||||
|
|
||||||
7. If, as a consequence of a court judgment or allegation of patent
|
9. Additional agreements
|
||||||
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.
|
|
||||||
|
|
||||||
If any portion of this section is held invalid or unenforceable under
|
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.
|
||||||
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.
|
|
||||||
|
|
||||||
It is not the purpose of this section to induce you to infringe any
|
10. Acceptance of the Licence
|
||||||
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.
|
|
||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
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.
|
||||||
be a consequence of the rest of this License.
|
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
|
11. Information to the public
|
||||||
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.
|
|
||||||
|
|
||||||
9. The Free Software Foundation may publish revised and/or new versions
|
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.
|
||||||
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.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Program
|
12. Termination of the Licence
|
||||||
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.
|
|
||||||
|
|
||||||
10. If you wish to incorporate parts of the Program into other free
|
The Licence and the rights granted hereunder will terminate automatically upon any breach by the Licensee of the terms of the Licence.
|
||||||
programs whose distribution conditions are different, write to the author
|
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.
|
||||||
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.
|
|
||||||
|
|
||||||
NO WARRANTY
|
13. Miscellaneous
|
||||||
|
|
||||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
Without prejudice of Article 9 above, the Licence represents the complete agreement between the Parties as to the Work.
|
||||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
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.
|
||||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
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.
|
||||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
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.
|
||||||
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.
|
|
||||||
|
|
||||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
14. Jurisdiction
|
||||||
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.
|
|
||||||
|
|
||||||
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
|
Without prejudice to specific agreement between parties,
|
||||||
possible use to the public, the best way to achieve this is to make it
|
- 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,
|
||||||
free software which everyone can redistribute and change under these terms.
|
- 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}
|
Appendix
|
||||||
Copyright (C) {year} {fullname}
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
Compatible Licences according to Article 5 EUPL are:
|
||||||
it under the terms of the GNU General Public License as published by
|
- GNU General Public License (GPL) v. 2, v. 3
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
- GNU Affero General Public License (AGPL) v. 3
|
||||||
(at your option) any later version.
|
- Open Software License (OSL) v. 2.1, v. 3.0
|
||||||
|
- Eclipse Public License (EPL) v. 1.0
|
||||||
This program is distributed in the hope that it will be useful,
|
- CeCILL v. 2.0, v. 2.1
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
- Mozilla Public Licence (MPL) v. 2
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
|
||||||
GNU General Public License for more details.
|
- 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
|
||||||
You should have received a copy of the GNU General Public License along
|
- Québec Free and Open-Source Licence - Reciprocity (LiLiQ-R) or Strong Reciprocity (LiLiQ-R+)
|
||||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
- 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.
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
- All other changes or additions to this Appendix require the production of a new EUPL version.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|||||||
182
README.md
182
README.md
@@ -1,50 +1,164 @@
|
|||||||
# Raspberry Pi Ad Blocker
|
<!-- markdownlint-configure-file { "MD004": { "style": "consistent" } } -->
|
||||||
**A black hole for ads, hence Pi-hole**
|
<!-- markdownlint-disable MD033 -->
|
||||||
|
#
|
||||||
|
|
||||||

|
<p align="center">
|
||||||
|
<a href="https://pi-hole.net/">
|
||||||
|
<img src="https://pi-hole.github.io/graphics/Vortex/Vortex_with_Wordmark.svg" width="150" height="260" alt="Pi-hole">
|
||||||
|
</a>
|
||||||
|
<br>
|
||||||
|
<strong>Network-wide ad blocking via your own Linux hardware</strong>
|
||||||
|
</p>
|
||||||
|
<!-- markdownlint-enable MD033 -->
|
||||||
|
|
||||||
The Pi-hole is a DNS/Web server that will **block ads for any device on your network**.
|
The Pi-hole® is a [DNS sinkhole](https://en.wikipedia.org/wiki/DNS_Sinkhole) that protects your devices from unwanted content without installing any client-side software.
|
||||||
|
|
||||||
## Coverage
|
- **Easy-to-install**: our versatile installer walks you through the process and takes less than ten minutes
|
||||||
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)!
|
- **Resolute**: content is blocked in _non-browser locations_, such as ad-laden mobile apps and smart TVs
|
||||||
|
- **Responsive**: seamlessly speeds up the feel of everyday browsing by caching DNS queries
|
||||||
|
- **Lightweight**: runs smoothly with [minimal hardware and software requirements](https://docs.pi-hole.net/main/prerequisites/)
|
||||||
|
- **Robust**: a command line interface that is quality assured for interoperability
|
||||||
|
- **Insightful**: a beautiful responsive Web Interface dashboard to view and control your Pi-hole
|
||||||
|
- **Versatile**: can optionally function as a [DHCP server](https://discourse.pi-hole.net/t/how-do-i-use-pi-holes-built-in-dhcp-server-and-why-would-i-want-to/3026), ensuring *all* your devices are protected automatically
|
||||||
|
- **Scalable**: [capable of handling hundreds of millions of queries](https://pi-hole.net/2017/05/24/how-much-traffic-can-pi-hole-handle/) when installed on server-grade hardware
|
||||||
|
- **Modern**: blocks ads over both IPv4 and IPv6
|
||||||
|
- **Free**: open source software that helps ensure _you_ are the sole person in control of your privacy
|
||||||
|
|
||||||
## Automated Install
|
-----
|
||||||
|
|
||||||
1. Install Raspbian
|
## One-Step Automated Install
|
||||||
2. Set a **static** IP address
|
|
||||||
3. Run the command below
|
|
||||||
|
|
||||||
```curl -s "https://raw.githubusercontent.com/jacobsalmela/pi-hole/master/automated%20install/basic-install.sh" | bash```
|
Those who want to get started quickly and conveniently may install Pi-hole using the following command:
|
||||||
|
|
||||||
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.
|
### `curl -sSL https://install.pi-hole.net | bash`
|
||||||
|
|
||||||
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).
|
## Alternative Install Methods
|
||||||
|
|
||||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3J2L3Z4DHW9UY "Donate")
|
Piping to `bash` is [controversial](https://pi-hole.net/2016/07/25/curling-and-piping-to-bash), as it prevents you from [reading code that is about to run](https://github.com/pi-hole/pi-hole/blob/master/automated%20install/basic-install.sh) on your system. Therefore, we provide these alternative installation methods which allow code review before installation:
|
||||||
|
|
||||||
## Gravity
|
### Method 1: Clone our repository and run
|
||||||
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 900,000 entries](http://jacobsalmela.com/block-millions-ads-network-wide-with-a-raspberry-pi-hole-2-0).
|
|
||||||
|
|
||||||
## Whitelist and blacklist
|
```bash
|
||||||
You can add a `whitelist.txt` or `blacklist.txt` in `/etc/pihole/` and the script will apply those files automatically.
|
git clone --depth 1 https://github.com/pi-hole/pi-hole.git Pi-hole
|
||||||
|
cd "Pi-hole/automated install/"
|
||||||
## Web Interface
|
sudo bash basic-install.sh
|
||||||
I am also working on a [Web interface](https://github.com/jacobsalmela/AdminLTE#pi-hole-admin-dashboard) so you can view stats and change settings.
|
|
||||||
|
|
||||||
## 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:
|
|
||||||
|
|
||||||
```
|
|
||||||
origin=/var/run/pihole
|
|
||||||
adList=/etc/dnsmasq.d/adList
|
|
||||||
```
|
```
|
||||||
|
|
||||||
See [this PR](https://github.com/jacobsalmela/pi-hole/pull/20) for more details.
|
### Method 2: Manually download the installer and run
|
||||||
|
|
||||||
### How It Works
|
```bash
|
||||||
A technical and detailed description can be found [here](http://jacobsalmela.com/block-millions-ads-network-wide-with-a-raspberry-pi-hole-2-0)!
|
wget -O basic-install.sh https://install.pi-hole.net
|
||||||
|
sudo bash basic-install.sh
|
||||||
|
```
|
||||||
|
### Method 3: Using Docker to deploy Pi-hole
|
||||||
|
Please refer to the [Pi-hole docker repo](https://github.com/pi-hole/docker-pi-hole) to use the Official Docker Images.
|
||||||
|
|
||||||
## Other Operating Systems
|
## [Post-install: Make your network take advantage of Pi-hole](https://docs.pi-hole.net/main/post-install/)
|
||||||
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.
|
|
||||||
|
|
||||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3J2L3Z4DHW9UY "Donate")
|
Once the installer has been run, you will need to [configure your router to have **DHCP clients use Pi-hole as their DNS server**](https://discourse.pi-hole.net/t/how-do-i-configure-my-devices-to-use-pi-hole-as-their-dns-server/245) which ensures that all devices connecting to your network will have content blocked without any further intervention.
|
||||||
|
|
||||||
|
If your router does not support setting the DNS server, you can [use Pi-hole's built-in DHCP server](https://discourse.pi-hole.net/t/how-do-i-use-pi-holes-built-in-dhcp-server-and-why-would-i-want-to/3026); be sure to disable DHCP on your router first (if it has that feature available).
|
||||||
|
|
||||||
|
As a last resort, you can manually set each device to use Pi-hole as their DNS server.
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
## Pi-hole is free but powered by your support
|
||||||
|
|
||||||
|
There are many reoccurring costs involved with maintaining free, open source, and privacy-respecting software; expenses which [our volunteer developers](https://github.com/orgs/pi-hole/people) pitch in to cover out-of-pocket. This is just one example of how strongly we feel about our software and the importance of keeping it maintained.
|
||||||
|
|
||||||
|
Make no mistake: **your support is absolutely vital to help keep us innovating!**
|
||||||
|
|
||||||
|
### [Donations](https://pi-hole.net/donate)
|
||||||
|
|
||||||
|
Donating using our Sponsor Button is **extremely helpful** in offsetting a portion of our monthly expenses:
|
||||||
|
|
||||||
|
### Alternative support
|
||||||
|
|
||||||
|
If you'd rather not donate (_which is okay!_), there are other ways you can help support us:
|
||||||
|
|
||||||
|
- [GitHub Sponsors](https://github.com/sponsors/pi-hole/)
|
||||||
|
- [Patreon](https://patreon.com/pihole)
|
||||||
|
- [Hetzner Cloud](https://hetzner.cloud/?ref=7aceisRX3AzA) _affiliate link_
|
||||||
|
- [Digital Ocean](https://www.digitalocean.com/?refcode=344d234950e1) _affiliate link_
|
||||||
|
- [Stickermule](https://www.stickermule.com/unlock?ref_id=9127301701&utm_medium=link&utm_source=invite) _earn a $10 credit after your first purchase_
|
||||||
|
- [Amazon US](http://www.amazon.com/exec/obidos/redirect-home/pihole09-20) _affiliate link_
|
||||||
|
- Spreading the word about our software and how you have benefited from it
|
||||||
|
|
||||||
|
### Contributing via GitHub
|
||||||
|
|
||||||
|
We welcome _everyone_ to contribute to issue reports, suggest new features, and create pull requests.
|
||||||
|
|
||||||
|
If you have something to add - anything from a typo through to a whole new feature, we're happy to check it out! Just make sure to fill out our template when submitting your request; the questions it asks will help the volunteers quickly understand what you're aiming to achieve.
|
||||||
|
|
||||||
|
You'll find that the [install script](https://github.com/pi-hole/pi-hole/blob/master/automated%20install/basic-install.sh) and the [debug script](https://github.com/pi-hole/pi-hole/blob/master/advanced/Scripts/piholeDebug.sh) have an abundance of comments, which will help you better understand how Pi-hole works. They're also a valuable resource to those who want to learn how to write scripts or code a program! We encourage anyone who likes to tinker to read through it and submit a pull request for us to review.
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
## Getting in touch with us
|
||||||
|
|
||||||
|
While we are primarily reachable on our [Discourse User Forum](https://discourse.pi-hole.net/), we can also be found on various social media outlets.
|
||||||
|
|
||||||
|
**Please be sure to check the FAQs** before starting a new discussion, as we do not have the spare time to reply to every request for assistance.
|
||||||
|
|
||||||
|
- [Frequently Asked Questions](https://discourse.pi-hole.net/c/faqs)
|
||||||
|
- [Feature Requests](https://discourse.pi-hole.net/c/feature-requests?order=votes)
|
||||||
|
- [Reddit](https://www.reddit.com/r/pihole/)
|
||||||
|
- [Twitter](https://twitter.com/The_Pi_hole)
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
## Breakdown of Features
|
||||||
|
|
||||||
|
### [Faster-than-light Engine](https://github.com/pi-hole/ftl)
|
||||||
|
|
||||||
|
[FTLDNS](https://github.com/pi-hole/ftl) is a lightweight, purpose-built daemon used to provide statistics needed for the Web Interface, and its API can be easily integrated into your own projects. As the name implies, FTLDNS does this all *very quickly*!
|
||||||
|
|
||||||
|
Some of the statistics you can integrate include:
|
||||||
|
|
||||||
|
- Total number of domains being blocked
|
||||||
|
- Total number of DNS queries today
|
||||||
|
- Total number of ads blocked today
|
||||||
|
- Percentage of ads blocked
|
||||||
|
- Unique domains
|
||||||
|
- Queries forwarded (to your chosen upstream DNS server)
|
||||||
|
- Queries cached
|
||||||
|
- Unique clients
|
||||||
|
|
||||||
|
Access the API via [`telnet`](https://github.com/pi-hole/FTL), the Web (`admin/api.php`) and Command Line (`pihole -c -j`). You can find out [more details over here](https://discourse.pi-hole.net/t/pi-hole-api/1863).
|
||||||
|
|
||||||
|
### The Command Line Interface
|
||||||
|
|
||||||
|
The [pihole](https://docs.pi-hole.net/core/pihole-command/) command has all the functionality necessary to fully administer the Pi-hole, without the need of the Web Interface. It's fast, user-friendly, and auditable by anyone with an understanding of `bash`.
|
||||||
|
|
||||||
|
Some notable features include:
|
||||||
|
|
||||||
|
- [Whitelisting, Blacklisting, and Regex](https://docs.pi-hole.net/core/pihole-command/#whitelisting-blacklisting-and-regex)
|
||||||
|
- [Debugging utility](https://docs.pi-hole.net/core/pihole-command/#debugger)
|
||||||
|
- [Viewing the live log file](https://docs.pi-hole.net/core/pihole-command/#tail)
|
||||||
|
- [Updating Ad Lists](https://docs.pi-hole.net/core/pihole-command/#gravity)
|
||||||
|
- [Querying Ad Lists for blocked domains](https://docs.pi-hole.net/core/pihole-command/#query)
|
||||||
|
- [Enabling and Disabling Pi-hole](https://docs.pi-hole.net/core/pihole-command/#enable-disable)
|
||||||
|
- ... and *many* more!
|
||||||
|
|
||||||
|
You can read our [Core Feature Breakdown](https://docs.pi-hole.net/core/pihole-command/#pi-hole-core) for more information.
|
||||||
|
|
||||||
|
### The Web Interface Dashboard
|
||||||
|
|
||||||
|
This [optional dashboard](https://github.com/pi-hole/AdminLTE) allows you to view stats, change settings, and configure your Pi-hole. It's the power of the Command Line Interface, with none of the learning curve!
|
||||||
|
|
||||||
|
Some notable features include:
|
||||||
|
|
||||||
|
- Mobile-friendly interface
|
||||||
|
- Password protection
|
||||||
|
- Detailed graphs and doughnut charts
|
||||||
|
- Top lists of domains and clients
|
||||||
|
- A filterable and sortable query log
|
||||||
|
- Long Term Statistics to view data over user-defined time ranges
|
||||||
|
- The ability to easily manage and configure Pi-hole features
|
||||||
|
- ... and all the main features of the Command Line Interface!
|
||||||
|
|
||||||
|
There are several ways to [access the dashboard](https://discourse.pi-hole.net/t/how-do-i-access-pi-holes-dashboard-admin-interface/3168):
|
||||||
|
|
||||||
|
1. `http://pi.hole/admin/` (when using Pi-hole as your DNS server)
|
||||||
|
2. `http://<IP_ADDPRESS_OF_YOUR_PI_HOLE>/admin/`
|
||||||
|
|||||||
42
advanced/01-pihole.conf
Normal file
42
advanced/01-pihole.conf
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Dnsmasq config for Pi-hole's FTLDNS
|
||||||
|
#
|
||||||
|
# This file is copyright under the latest version of the EUPL.
|
||||||
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# 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 SEPARATE CONFIG FILE #
|
||||||
|
# WITHIN /etc/dnsmasq.d/yourname.conf #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
addn-hosts=/etc/pihole/local.list
|
||||||
|
addn-hosts=/etc/pihole/custom.list
|
||||||
|
|
||||||
|
domain-needed
|
||||||
|
|
||||||
|
localise-queries
|
||||||
|
|
||||||
|
bogus-priv
|
||||||
|
|
||||||
|
no-resolv
|
||||||
|
|
||||||
|
server=@DNS1@
|
||||||
|
server=@DNS2@
|
||||||
|
|
||||||
|
interface=@INT@
|
||||||
|
|
||||||
|
cache-size=@CACHE_SIZE@
|
||||||
|
|
||||||
|
log-queries
|
||||||
|
log-facility=/var/log/pihole.log
|
||||||
|
|
||||||
|
log-async
|
||||||
42
advanced/06-rfc6761.conf
Normal file
42
advanced/06-rfc6761.conf
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# Pi-hole: A black hole for Internet advertisements
|
||||||
|
# (c) 2021 Pi-hole, LLC (https://pi-hole.net)
|
||||||
|
# Network-wide ad blocking via your own hardware.
|
||||||
|
#
|
||||||
|
# RFC 6761 config file 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 POPULATED BY PI-HOLE INSTALL/UPDATE PROCEDURE. #
|
||||||
|
# ANY CHANGES MADE TO THIS FILE AFTER INSTALL WILL BE LOST ON THE NEXT UPDATE #
|
||||||
|
# #
|
||||||
|
# CHANGES SHOULD BE MADE IN A SEPARATE CONFIG FILE #
|
||||||
|
# WITHIN /etc/dnsmasq.d/yourname.conf #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# RFC 6761: Caching DNS servers SHOULD recognize
|
||||||
|
# test, localhost, invalid
|
||||||
|
# names as special and SHOULD NOT attempt to look up NS records for them, or
|
||||||
|
# otherwise query authoritative DNS servers in an attempt to resolve these
|
||||||
|
# names.
|
||||||
|
server=/test/
|
||||||
|
server=/localhost/
|
||||||
|
server=/invalid/
|
||||||
|
|
||||||
|
# The same RFC requests something similar for
|
||||||
|
# 10.in-addr.arpa. 21.172.in-addr.arpa. 27.172.in-addr.arpa.
|
||||||
|
# 16.172.in-addr.arpa. 22.172.in-addr.arpa. 28.172.in-addr.arpa.
|
||||||
|
# 17.172.in-addr.arpa. 23.172.in-addr.arpa. 29.172.in-addr.arpa.
|
||||||
|
# 18.172.in-addr.arpa. 24.172.in-addr.arpa. 30.172.in-addr.arpa.
|
||||||
|
# 19.172.in-addr.arpa. 25.172.in-addr.arpa. 31.172.in-addr.arpa.
|
||||||
|
# 20.172.in-addr.arpa. 26.172.in-addr.arpa. 168.192.in-addr.arpa.
|
||||||
|
# Pi-hole implements this via the dnsmasq option "bogus-priv" (see
|
||||||
|
# 01-pihole.conf) because this also covers IPv6.
|
||||||
|
|
||||||
|
# OpenWRT furthermore blocks bind, local, onion domains
|
||||||
|
# see https://git.openwrt.org/?p=openwrt/openwrt.git;a=blob_plain;f=package/network/services/dnsmasq/files/rfc6761.conf;hb=HEAD
|
||||||
|
# and https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml
|
||||||
|
# We do not include the ".local" rule ourselves, see https://github.com/pi-hole/pi-hole/pull/4282#discussion_r689112972
|
||||||
|
server=/bind/
|
||||||
|
server=/onion/
|
||||||
49
advanced/Scripts/COL_TABLE
Normal file
49
advanced/Scripts/COL_TABLE
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# Determine if terminal is capable of showing colors
|
||||||
|
if [[ -t 1 ]] && [[ $(tput colors) -ge 8 ]]; then
|
||||||
|
# Bold and underline may not show up on all clients
|
||||||
|
# If something MUST be emphasized, use both
|
||||||
|
COL_BOLD='[1m'
|
||||||
|
COL_ULINE='[4m'
|
||||||
|
|
||||||
|
COL_NC='[0m'
|
||||||
|
COL_GRAY='[90m'
|
||||||
|
COL_RED='[91m'
|
||||||
|
COL_GREEN='[32m'
|
||||||
|
COL_YELLOW='[33m'
|
||||||
|
COL_BLUE='[94m'
|
||||||
|
COL_PURPLE='[95m'
|
||||||
|
COL_CYAN='[96m'
|
||||||
|
else
|
||||||
|
# Provide empty variables for `set -u`
|
||||||
|
COL_BOLD=""
|
||||||
|
COL_ULINE=""
|
||||||
|
|
||||||
|
COL_NC=""
|
||||||
|
COL_GRAY=""
|
||||||
|
COL_RED=""
|
||||||
|
COL_GREEN=""
|
||||||
|
COL_YELLOW=""
|
||||||
|
COL_BLUE=""
|
||||||
|
COL_PURPLE=""
|
||||||
|
COL_CYAN=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Deprecated variables
|
||||||
|
COL_WHITE="${COL_BOLD}"
|
||||||
|
COL_BLACK="${COL_NC}"
|
||||||
|
COL_LIGHT_BLUE="${COL_BLUE}"
|
||||||
|
COL_LIGHT_GREEN="${COL_GREEN}"
|
||||||
|
COL_LIGHT_CYAN="${COL_CYAN}"
|
||||||
|
COL_LIGHT_RED="${COL_RED}"
|
||||||
|
COL_URG_RED="${COL_RED}${COL_BOLD}${COL_ULINE}"
|
||||||
|
COL_LIGHT_PURPLE="${COL_PURPLE}"
|
||||||
|
COL_BROWN="${COL_YELLOW}"
|
||||||
|
COL_LIGHT_GRAY="${COL_GRAY}"
|
||||||
|
COL_DARK_GRAY="${COL_GRAY}"
|
||||||
|
|
||||||
|
TICK="[${COL_GREEN}✓${COL_NC}]"
|
||||||
|
CROSS="[${COL_RED}✗${COL_NC}]"
|
||||||
|
INFO="[i]"
|
||||||
|
QST="[?]"
|
||||||
|
DONE="${COL_GREEN} done!${COL_NC}"
|
||||||
|
OVER="\\r[K"
|
||||||
@@ -1,28 +1,575 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
# Displays Pi-hole stats on the Adafruit PiTFT 2.8" touch screen
|
# shellcheck disable=SC1090,SC1091
|
||||||
# Set the pi user to log in automatically and run this script from /etc/profile
|
# Pi-hole: A black hole for Internet advertisements
|
||||||
for (( ; ; ))
|
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||||
do
|
# Network-wide ad blocking via your own hardware.
|
||||||
clear
|
#
|
||||||
# Displays a colorful Pi-hole logo
|
# Calculates stats and displays to an LCD
|
||||||
toilet -f small -F gay Pi-hole
|
#
|
||||||
echo " $(ifconfig eth0 | awk '/inet addr/ {print $2}' | cut -d':' -f2)"
|
# This file is copyright under the latest version of the EUPL.
|
||||||
echo ""
|
# Please see LICENSE file for your rights under this license.
|
||||||
uptime | cut -d' ' -f11-
|
LC_ALL=C
|
||||||
echo "-------------------------------"
|
LC_NUMERIC=C
|
||||||
# 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")
|
# Retrieve stats from FTL engine
|
||||||
todaysQueryCount=$(cat /var/log/pihole.log | grep "$today" | awk '/query/ {print $7}' | wc -l)
|
pihole-FTL() {
|
||||||
todaysQueryCountV4=$(cat /var/log/pihole.log | grep "$today" | awk '/query/ && /\[A\]/ {print $7}' | wc -l)
|
local ftl_port LINE
|
||||||
todaysQueryCountV6=$(cat /var/log/pihole.log | grep "$today" | awk '/query/ && /\[AAAA\]/ {print $7}' | wc -l)
|
ftl_port=$(cat /run/pihole-FTL.port 2> /dev/null)
|
||||||
todaysAdsEliminated=$(cat /var/log/pihole.log | grep "$today" | awk '/\/etc\/pihole\/gravity.list/ {print $7}' | wc -l)
|
if [[ -n "$ftl_port" ]]; then
|
||||||
dividend=$(echo "$todaysAdsEliminated/$todaysQueryCount" | bc -l)
|
# Open connection to FTL
|
||||||
fp=$(echo "$dividend*100" | bc -l)
|
exec 3<>"/dev/tcp/127.0.0.1/$ftl_port"
|
||||||
percentAds=$(echo ${fp:0:4})
|
|
||||||
|
|
||||||
echo "Queries: $todaysQueryCountV4 / $todaysQueryCountV6"
|
# Test if connection is open
|
||||||
echo "Pi-holed: $todaysAdsEliminated ($percentAds%)"
|
if { "true" >&3; } 2> /dev/null; then
|
||||||
sleep 5
|
# Send command to FTL and ask to quit when finished
|
||||||
done
|
echo -e ">$1 >quit" >&3
|
||||||
|
|
||||||
|
# Read input until we received an empty string and the connection is
|
||||||
|
# closed
|
||||||
|
read -r -t 1 LINE <&3
|
||||||
|
until [[ -z "${LINE}" ]] && [[ ! -t 3 ]]; do
|
||||||
|
echo "$LINE" >&1
|
||||||
|
read -r -t 1 LINE <&3
|
||||||
|
done
|
||||||
|
|
||||||
|
# Close connection
|
||||||
|
exec 3>&-
|
||||||
|
exec 3<&-
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "0"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Print spaces to align right-side additional text
|
||||||
|
printFunc() {
|
||||||
|
local text_last
|
||||||
|
|
||||||
|
title="$1"
|
||||||
|
title_len="${#title}"
|
||||||
|
|
||||||
|
text_main="$2"
|
||||||
|
text_main_nocol="$text_main"
|
||||||
|
if [[ "${text_main:0:1}" == "" ]]; then
|
||||||
|
text_main_nocol=$(sed 's/\[[0-9;]\{1,5\}m//g' <<< "$text_main")
|
||||||
|
fi
|
||||||
|
text_main_len="${#text_main_nocol}"
|
||||||
|
|
||||||
|
text_addn="$3"
|
||||||
|
if [[ "$text_addn" == "last" ]]; then
|
||||||
|
text_addn=""
|
||||||
|
text_last="true"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If there is additional text, define max length of text_main
|
||||||
|
if [[ -n "$text_addn" ]]; then
|
||||||
|
case "$scr_cols" in
|
||||||
|
[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-4]) text_main_max_len="9";;
|
||||||
|
4[5-9]) text_main_max_len="14";;
|
||||||
|
*) text_main_max_len="19";;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ -z "$text_addn" ]] && text_main_max_len="$(( scr_cols - title_len ))"
|
||||||
|
|
||||||
|
# Remove excess characters from main text
|
||||||
|
if [[ "$text_main_len" -gt "$text_main_max_len" ]]; then
|
||||||
|
# Trim text without colors
|
||||||
|
text_main_trim="${text_main_nocol:0:$text_main_max_len}"
|
||||||
|
# Replace with trimmed text
|
||||||
|
text_main="${text_main/$text_main_nocol/$text_main_trim}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine amount of spaces for each line
|
||||||
|
if [[ -n "$text_last" ]]; then
|
||||||
|
# Move cursor to end of screen
|
||||||
|
spc_num=$(( scr_cols - ( title_len + text_main_len ) ))
|
||||||
|
else
|
||||||
|
spc_num=$(( text_main_max_len - text_main_len ))
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ "$spc_num" -le 0 ]] && spc_num="0"
|
||||||
|
spc=$(printf "%${spc_num}s")
|
||||||
|
#spc="${spc// /.}" # Debug: Visualize spaces
|
||||||
|
|
||||||
|
printf "%s%s$spc" "$title" "$text_main"
|
||||||
|
|
||||||
|
if [[ -n "$text_addn" ]]; then
|
||||||
|
printf "%s(%s)%s\\n" "$COL_NC$COL_DARK_GRAY" "$text_addn" "$COL_NC"
|
||||||
|
else
|
||||||
|
# Do not print trailing newline on final line
|
||||||
|
[[ -z "$text_last" ]] && printf "%s\\n" "$COL_NC"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Perform on first Chrono run (not for JSON formatted string)
|
||||||
|
get_init_stats() {
|
||||||
|
calcFunc(){ awk "BEGIN {print $*}" 2> /dev/null; }
|
||||||
|
|
||||||
|
# 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 Color 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 throttle state (RPi 3B only) & model number, or OS distro info
|
||||||
|
if command -v vcgencmd &> /dev/null; then
|
||||||
|
local sys_throttle_raw
|
||||||
|
local sys_rev_raw
|
||||||
|
|
||||||
|
sys_throttle_raw=$(vgt=$(sudo vcgencmd get_throttled); echo "${vgt##*x}")
|
||||||
|
|
||||||
|
# Active Throttle Notice: https://bit.ly/2gnunOo
|
||||||
|
if [[ "$sys_throttle_raw" != "0" ]]; then
|
||||||
|
case "$sys_throttle_raw" in
|
||||||
|
*0001) thr_type="${COL_YELLOW}Under Voltage";;
|
||||||
|
*0002) thr_type="${COL_LIGHT_BLUE}Arm Freq Cap";;
|
||||||
|
*0003) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_BLUE}AFC";;
|
||||||
|
*0004) thr_type="${COL_LIGHT_RED}Throttled";;
|
||||||
|
*0005) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";;
|
||||||
|
*0006) thr_type="${COL_LIGHT_BLUE}AFC${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";;
|
||||||
|
*0007) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_BLUE}AFC${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";;
|
||||||
|
esac
|
||||||
|
[[ -n "$thr_type" ]] && sys_throttle="$thr_type${COL_DARK_GRAY}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
sys_rev_raw=$(awk '/Revision/ {print $3}' < /proc/cpuinfo)
|
||||||
|
case "$sys_rev_raw" 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
|
||||||
|
a020d3) 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)
|
||||||
|
|
||||||
|
# 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
|
||||||
|
# Do not source setupVars if file does not exist
|
||||||
|
[[ -n "$setupVars" ]] && source "$setupVars"
|
||||||
|
|
||||||
|
mapfile -t 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]}"
|
||||||
|
if [[ ${#ph_ver_raw[@]} -eq 2 ]]; then
|
||||||
|
# AdminLTE not installed
|
||||||
|
ph_lte_ver="(not installed)"
|
||||||
|
ph_ftl_ver="${ph_ver_raw[1]}"
|
||||||
|
else
|
||||||
|
ph_lte_ver="${ph_ver_raw[1]}"
|
||||||
|
ph_ftl_ver="${ph_ver_raw[2]}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
ph_core_ver="-1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
sys_name=$(hostname)
|
||||||
|
|
||||||
|
[[ -n "$TEMPERATUREUNIT" ]] && temp_unit="${TEMPERATUREUNIT^^}" || temp_unit="C"
|
||||||
|
|
||||||
|
# Get storage stats for partition mounted on /
|
||||||
|
read -r -a 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=$(ip route | grep default | cut -d ' ' -f 3 | head -n 1)
|
||||||
|
|
||||||
|
# Get DHCP stats, if feature is enabled
|
||||||
|
if [[ "$DHCP_ACTIVE" == "true" ]]; then
|
||||||
|
ph_dhcp_max=$(( ${DHCP_END##*.} - ${DHCP_START##*.} + 1 ))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get DNS server count
|
||||||
|
dns_count="0"
|
||||||
|
[[ -n "${PIHOLE_DNS_1}" ]] && dns_count=$((dns_count+1))
|
||||||
|
[[ -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+"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get screen size
|
||||||
|
read -r -a scr_size <<< "$(stty size 2>/dev/null || echo 24 80)"
|
||||||
|
scr_lines="${scr_size[0]}"
|
||||||
|
scr_cols="${scr_size[1]}"
|
||||||
|
|
||||||
|
# Determine Chronometer size behavior
|
||||||
|
if [[ "$scr_cols" -ge 58 ]]; then
|
||||||
|
chrono_width="large"
|
||||||
|
elif [[ "$scr_cols" -gt 40 ]]; then
|
||||||
|
chrono_width="medium"
|
||||||
|
else
|
||||||
|
chrono_width="small"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine max length of divider string
|
||||||
|
scr_line_len=$(( scr_cols - 2 ))
|
||||||
|
[[ "$scr_line_len" -ge 58 ]] && scr_line_len="58"
|
||||||
|
scr_line_str=$(printf "%${scr_line_len}s")
|
||||||
|
scr_line_str="${scr_line_str// /—}"
|
||||||
|
|
||||||
|
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% as active
|
||||||
|
# shellcheck disable=SC2009
|
||||||
|
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 $2;exit}')
|
||||||
|
cpu_mhz=$(printf "%.0f" "${cpu_mhz//[[:space:]]/}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine whether to display CPU clock speed as MHz or GHz
|
||||||
|
if [[ -n "$cpu_mhz" ]]; then
|
||||||
|
[[ "$cpu_mhz" -le "999" ]] && cpu_freq="$cpu_mhz MHz" || cpu_freq="$(printf "%.1f" $(calcFunc "$cpu_mhz"/1000)) GHz"
|
||||||
|
[[ "${cpu_freq}" == *".0"* ]] && cpu_freq="${cpu_freq/.0/}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine color 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
|
||||||
|
|
||||||
|
read -r -a 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}Offline"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$DHCP_ACTIVE" == "true" ]]; then
|
||||||
|
local ph_dhcp_range
|
||||||
|
|
||||||
|
ph_dhcp_range=$(seq -s "|" -f "${DHCP_START%.*}.%g" "${DHCP_START##*.}" "${DHCP_END##*.}")
|
||||||
|
|
||||||
|
# Count dynamic leases from available range, and not static leases
|
||||||
|
ph_dhcp_num=$(grep -cE "$ph_dhcp_range" "/etc/pihole/dhcp.leases")
|
||||||
|
ph_dhcp_percent=$(( ph_dhcp_num * 100 / ph_dhcp_max ))
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
get_ftl_stats() {
|
||||||
|
local stats_raw
|
||||||
|
|
||||||
|
mapfile -t stats_raw < <(pihole-FTL "stats")
|
||||||
|
domains_being_blocked_raw="${stats_raw[0]#* }"
|
||||||
|
dns_queries_today_raw="${stats_raw[1]#* }"
|
||||||
|
ads_blocked_today_raw="${stats_raw[2]#* }"
|
||||||
|
ads_percentage_today_raw="${stats_raw[3]#* }"
|
||||||
|
queries_forwarded_raw="${stats_raw[5]#* }"
|
||||||
|
queries_cached_raw="${stats_raw[6]#* }"
|
||||||
|
|
||||||
|
# Only retrieve these stats when not called from jsonFunc
|
||||||
|
if [[ -z "$1" ]]; then
|
||||||
|
local top_ad_raw
|
||||||
|
local top_domain_raw
|
||||||
|
local top_client_raw
|
||||||
|
|
||||||
|
domains_being_blocked=$(printf "%.0f\\n" "${domains_being_blocked_raw}" 2> /dev/null)
|
||||||
|
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}")
|
||||||
|
queries_cached_percentage=$(printf "%.0f\\n" "$(calcFunc "$queries_cached_raw * 100 / ( $queries_forwarded_raw + $queries_cached_raw )")")
|
||||||
|
recent_blocked=$(pihole-FTL recentBlocked)
|
||||||
|
read -r -a top_ad_raw <<< "$(pihole-FTL "top-ads (1)")"
|
||||||
|
read -r -a top_domain_raw <<< "$(pihole-FTL "top-domains (1)")"
|
||||||
|
read -r -a top_client_raw <<< "$(pihole-FTL "top-clients (1)")"
|
||||||
|
|
||||||
|
top_ad="${top_ad_raw[2]}"
|
||||||
|
top_domain="${top_domain_raw[2]}"
|
||||||
|
if [[ "${top_client_raw[3]}" ]]; then
|
||||||
|
top_client="${top_client_raw[3]}"
|
||||||
|
else
|
||||||
|
top_client="${top_client_raw[2]}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
get_strings() {
|
||||||
|
# Expand or contract strings depending on screen size
|
||||||
|
if [[ "$chrono_width" == "large" ]]; then
|
||||||
|
phc_str=" ${COL_DARK_GRAY}Core"
|
||||||
|
lte_str=" ${COL_DARK_GRAY}Web"
|
||||||
|
ftl_str=" ${COL_DARK_GRAY}FTL"
|
||||||
|
api_str="${COL_LIGHT_RED}API Offline"
|
||||||
|
|
||||||
|
host_info="$sys_type"
|
||||||
|
sys_info="$sys_throttle"
|
||||||
|
sys_info2="Active: $cpu_taskact of $cpu_tasks tasks"
|
||||||
|
used_str="Used: "
|
||||||
|
leased_str="Leased: "
|
||||||
|
domains_being_blocked=$(printf "%'.0f" "$domains_being_blocked")
|
||||||
|
ads_blocked_today=$(printf "%'.0f" "$ads_blocked_today")
|
||||||
|
dns_queries_today=$(printf "%'.0f" "$dns_queries_today")
|
||||||
|
ph_info="Blocking: $domains_being_blocked sites"
|
||||||
|
total_str="Total: "
|
||||||
|
else
|
||||||
|
phc_str=" ${COL_DARK_GRAY}Core"
|
||||||
|
lte_str=" ${COL_DARK_GRAY}Web"
|
||||||
|
ftl_str=" ${COL_DARK_GRAY}FTL"
|
||||||
|
api_str="${COL_LIGHT_RED}API Down"
|
||||||
|
ph_info="$domains_being_blocked blocked"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ "$sys_cores" -ne 1 ]] && sys_cores_txt="${sys_cores}x "
|
||||||
|
cpu_info="$sys_cores_txt$cpu_freq$cpu_temp_str"
|
||||||
|
ram_info="$used_str$(hrBytes "$ram_used") of $(hrBytes "$ram_total")"
|
||||||
|
disk_info="$used_str$(hrBytes "$disk_used") of $(hrBytes "$disk_total")"
|
||||||
|
|
||||||
|
lan_info="Gateway: $net_gateway"
|
||||||
|
dhcp_info="$leased_str$ph_dhcp_num of $ph_dhcp_max"
|
||||||
|
|
||||||
|
ads_info="$total_str$ads_blocked_today of $dns_queries_today"
|
||||||
|
dns_info="$dns_count DNS servers"
|
||||||
|
|
||||||
|
[[ "$recent_blocked" == "0" ]] && recent_blocked="${COL_LIGHT_RED}FTL offline${COL_NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
chronoFunc() {
|
||||||
|
local extra_arg="$1"
|
||||||
|
local extra_value="$2"
|
||||||
|
|
||||||
|
get_init_stats
|
||||||
|
|
||||||
|
for (( ; ; )); do
|
||||||
|
get_sys_stats
|
||||||
|
get_ftl_stats
|
||||||
|
get_strings
|
||||||
|
|
||||||
|
# Strip excess development version numbers
|
||||||
|
if [[ "$ph_core_ver" != "-1" ]]; then
|
||||||
|
phc_ver_str="$phc_str: ${ph_core_ver%-*}${COL_NC}"
|
||||||
|
lte_ver_str="$lte_str: ${ph_lte_ver%-*}${COL_NC}"
|
||||||
|
ftl_ver_str="$ftl_str: ${ph_ftl_ver%-*}${COL_NC}"
|
||||||
|
else
|
||||||
|
phc_ver_str="$phc_str: $api_str${COL_NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get refresh number
|
||||||
|
if [[ "${extra_arg}" = "refresh" ]]; then
|
||||||
|
num="${extra_value}"
|
||||||
|
num_str="Refresh set for every $num seconds"
|
||||||
|
else
|
||||||
|
num_str=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
clear
|
||||||
|
|
||||||
|
# Remove exit message heading on third refresh
|
||||||
|
if [[ "$count" -le 2 ]] && [[ "${extra_arg}" != "exit" ]]; then
|
||||||
|
echo -e " ${COL_LIGHT_GREEN}Pi-hole Chronometer${COL_NC}
|
||||||
|
$num_str
|
||||||
|
${COL_LIGHT_RED}Press Ctrl-C to exit${COL_NC}
|
||||||
|
${COL_DARK_GRAY}$scr_line_str${COL_NC}"
|
||||||
|
else
|
||||||
|
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$phc_ver_str\\n[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$lte_ver_str\\n[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$ftl_ver_str\\n ${COL_DARK_GRAY}$scr_line_str${COL_NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printFunc " Hostname: " "$sys_name" "$host_info"
|
||||||
|
printFunc " Uptime: " "$sys_uptime" "$sys_info"
|
||||||
|
printFunc " Task Load: " "$sys_loadavg" "$sys_info2"
|
||||||
|
printFunc " CPU usage: " "$cpu_perc%" "$cpu_info"
|
||||||
|
printFunc " RAM usage: " "$ram_perc%" "$ram_info"
|
||||||
|
printFunc " HDD usage: " "$disk_perc" "$disk_info"
|
||||||
|
|
||||||
|
if [[ "$DHCP_ACTIVE" == "true" ]]; then
|
||||||
|
printFunc "DHCP usage: " "$ph_dhcp_percent%" "$dhcp_info"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printFunc " Pi-hole: " "$ph_status" "$ph_info"
|
||||||
|
printFunc " Ads Today: " "$ads_percentage_today%" "$ads_info"
|
||||||
|
printFunc "Local Qrys: " "$queries_cached_percentage%" "$dns_info"
|
||||||
|
|
||||||
|
printFunc " Blocked: " "$recent_blocked"
|
||||||
|
printFunc "Top Advert: " "$top_ad"
|
||||||
|
|
||||||
|
# Provide more stats on screens with more lines
|
||||||
|
if [[ "$scr_lines" -eq 17 ]]; then
|
||||||
|
if [[ "$DHCP_ACTIVE" == "true" ]]; then
|
||||||
|
printFunc "Top Domain: " "$top_domain" "last"
|
||||||
|
else
|
||||||
|
print_client="true"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_client="true"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$print_client" ]]; then
|
||||||
|
printFunc "Top Domain: " "$top_domain"
|
||||||
|
printFunc "Top Client: " "$top_client" "last"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Handle exit/refresh options
|
||||||
|
if [[ "${extra_arg}" == "exit" ]]; then
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
if [[ "${extra_arg}" == "refresh" ]]; then
|
||||||
|
sleep "$num"
|
||||||
|
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 without refreshing
|
||||||
|
-h, --help Display this help text"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ $# = 0 ]]; then
|
||||||
|
chronoFunc
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
"-j" | "--json" ) jsonFunc;;
|
||||||
|
"-h" | "--help" ) helpFunc;;
|
||||||
|
"-r" | "--refresh" ) chronoFunc refresh "$2";;
|
||||||
|
"-e" | "--exit" ) chronoFunc exit;;
|
||||||
|
* ) helpFunc "?";;
|
||||||
|
esac
|
||||||
|
|||||||
131
advanced/Scripts/database_migration/gravity-db.sh
Executable file
131
advanced/Scripts/database_migration/gravity-db.sh
Executable file
@@ -0,0 +1,131 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
|
||||||
|
# Pi-hole: A black hole for Internet advertisements
|
||||||
|
# (c) 2019 Pi-hole, LLC (https://pi-hole.net)
|
||||||
|
# Network-wide ad blocking via your own hardware.
|
||||||
|
#
|
||||||
|
# Updates gravity.db database
|
||||||
|
#
|
||||||
|
# This file is copyright under the latest version of the EUPL.
|
||||||
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
|
readonly scriptPath="/etc/.pihole/advanced/Scripts/database_migration/gravity"
|
||||||
|
|
||||||
|
upgrade_gravityDB(){
|
||||||
|
local database piholeDir auditFile version
|
||||||
|
database="${1}"
|
||||||
|
piholeDir="${2}"
|
||||||
|
auditFile="${piholeDir}/auditlog.list"
|
||||||
|
|
||||||
|
# Get database version
|
||||||
|
version="$(sqlite3 "${database}" "SELECT \"value\" FROM \"info\" WHERE \"property\" = 'version';")"
|
||||||
|
|
||||||
|
if [[ "$version" == "1" ]]; then
|
||||||
|
# This migration script upgrades the gravity.db file by
|
||||||
|
# adding the domain_audit table
|
||||||
|
echo -e " ${INFO} Upgrading gravity database from version 1 to 2"
|
||||||
|
sqlite3 "${database}" < "${scriptPath}/1_to_2.sql"
|
||||||
|
version=2
|
||||||
|
|
||||||
|
# Store audit domains in database table
|
||||||
|
if [ -e "${auditFile}" ]; then
|
||||||
|
echo -e " ${INFO} Migrating content of ${auditFile} into new database"
|
||||||
|
# database_table_from_file is defined in gravity.sh
|
||||||
|
database_table_from_file "domain_audit" "${auditFile}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [[ "$version" == "2" ]]; then
|
||||||
|
# This migration script upgrades the gravity.db file by
|
||||||
|
# renaming the regex table to regex_blacklist, and
|
||||||
|
# creating a new regex_whitelist table + corresponding linking table and views
|
||||||
|
echo -e " ${INFO} Upgrading gravity database from version 2 to 3"
|
||||||
|
sqlite3 "${database}" < "${scriptPath}/2_to_3.sql"
|
||||||
|
version=3
|
||||||
|
fi
|
||||||
|
if [[ "$version" == "3" ]]; then
|
||||||
|
# This migration script unifies the formally separated domain
|
||||||
|
# lists into a single table with a UNIQUE domain constraint
|
||||||
|
echo -e " ${INFO} Upgrading gravity database from version 3 to 4"
|
||||||
|
sqlite3 "${database}" < "${scriptPath}/3_to_4.sql"
|
||||||
|
version=4
|
||||||
|
fi
|
||||||
|
if [[ "$version" == "4" ]]; then
|
||||||
|
# This migration script upgrades the gravity and list views
|
||||||
|
# implementing necessary changes for per-client blocking
|
||||||
|
echo -e " ${INFO} Upgrading gravity database from version 4 to 5"
|
||||||
|
sqlite3 "${database}" < "${scriptPath}/4_to_5.sql"
|
||||||
|
version=5
|
||||||
|
fi
|
||||||
|
if [[ "$version" == "5" ]]; then
|
||||||
|
# This migration script upgrades the adlist view
|
||||||
|
# to return an ID used in gravity.sh
|
||||||
|
echo -e " ${INFO} Upgrading gravity database from version 5 to 6"
|
||||||
|
sqlite3 "${database}" < "${scriptPath}/5_to_6.sql"
|
||||||
|
version=6
|
||||||
|
fi
|
||||||
|
if [[ "$version" == "6" ]]; then
|
||||||
|
# This migration script adds a special group with ID 0
|
||||||
|
# which is automatically associated to all clients not
|
||||||
|
# having their own group assignments
|
||||||
|
echo -e " ${INFO} Upgrading gravity database from version 6 to 7"
|
||||||
|
sqlite3 "${database}" < "${scriptPath}/6_to_7.sql"
|
||||||
|
version=7
|
||||||
|
fi
|
||||||
|
if [[ "$version" == "7" ]]; then
|
||||||
|
# This migration script recreated the group table
|
||||||
|
# to ensure uniqueness on the group name
|
||||||
|
# We also add date_added and date_modified columns
|
||||||
|
echo -e " ${INFO} Upgrading gravity database from version 7 to 8"
|
||||||
|
sqlite3 "${database}" < "${scriptPath}/7_to_8.sql"
|
||||||
|
version=8
|
||||||
|
fi
|
||||||
|
if [[ "$version" == "8" ]]; then
|
||||||
|
# This migration fixes some issues that were introduced
|
||||||
|
# in the previous migration script.
|
||||||
|
echo -e " ${INFO} Upgrading gravity database from version 8 to 9"
|
||||||
|
sqlite3 "${database}" < "${scriptPath}/8_to_9.sql"
|
||||||
|
version=9
|
||||||
|
fi
|
||||||
|
if [[ "$version" == "9" ]]; then
|
||||||
|
# This migration drops unused tables and creates triggers to remove
|
||||||
|
# obsolete groups assignments when the linked items are deleted
|
||||||
|
echo -e " ${INFO} Upgrading gravity database from version 9 to 10"
|
||||||
|
sqlite3 "${database}" < "${scriptPath}/9_to_10.sql"
|
||||||
|
version=10
|
||||||
|
fi
|
||||||
|
if [[ "$version" == "10" ]]; then
|
||||||
|
# This adds timestamp and an optional comment field to the client table
|
||||||
|
# These fields are only temporary and will be replaces by the columns
|
||||||
|
# defined in gravity.db.sql during gravity swapping. We add them here
|
||||||
|
# to keep the copying process generic (needs the same columns in both the
|
||||||
|
# source and the destination databases).
|
||||||
|
echo -e " ${INFO} Upgrading gravity database from version 10 to 11"
|
||||||
|
sqlite3 "${database}" < "${scriptPath}/10_to_11.sql"
|
||||||
|
version=11
|
||||||
|
fi
|
||||||
|
if [[ "$version" == "11" ]]; then
|
||||||
|
# Rename group 0 from "Unassociated" to "Default"
|
||||||
|
echo -e " ${INFO} Upgrading gravity database from version 11 to 12"
|
||||||
|
sqlite3 "${database}" < "${scriptPath}/11_to_12.sql"
|
||||||
|
version=12
|
||||||
|
fi
|
||||||
|
if [[ "$version" == "12" ]]; then
|
||||||
|
# Add column date_updated to adlist table
|
||||||
|
echo -e " ${INFO} Upgrading gravity database from version 12 to 13"
|
||||||
|
sqlite3 "${database}" < "${scriptPath}/12_to_13.sql"
|
||||||
|
version=13
|
||||||
|
fi
|
||||||
|
if [[ "$version" == "13" ]]; then
|
||||||
|
# Add columns number and status to adlist table
|
||||||
|
echo -e " ${INFO} Upgrading gravity database from version 13 to 14"
|
||||||
|
sqlite3 "${database}" < "${scriptPath}/13_to_14.sql"
|
||||||
|
version=14
|
||||||
|
fi
|
||||||
|
if [[ "$version" == "14" ]]; then
|
||||||
|
# Changes the vw_adlist created in 5_to_6
|
||||||
|
echo -e " ${INFO} Upgrading gravity database from version 14 to 15"
|
||||||
|
sqlite3 "${database}" < "${scriptPath}/14_to_15.sql"
|
||||||
|
version=15
|
||||||
|
fi
|
||||||
|
}
|
||||||
16
advanced/Scripts/database_migration/gravity/10_to_11.sql
Normal file
16
advanced/Scripts/database_migration/gravity/10_to_11.sql
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
.timeout 30000
|
||||||
|
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE client ADD COLUMN date_added INTEGER;
|
||||||
|
ALTER TABLE client ADD COLUMN date_modified INTEGER;
|
||||||
|
ALTER TABLE client ADD COLUMN comment TEXT;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_client_update AFTER UPDATE ON client
|
||||||
|
BEGIN
|
||||||
|
UPDATE client SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE id = NEW.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
UPDATE info SET value = 11 WHERE property = 'version';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
19
advanced/Scripts/database_migration/gravity/11_to_12.sql
Normal file
19
advanced/Scripts/database_migration/gravity/11_to_12.sql
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
.timeout 30000
|
||||||
|
|
||||||
|
PRAGMA FOREIGN_KEYS=OFF;
|
||||||
|
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
UPDATE "group" SET name = 'Default' WHERE id = 0;
|
||||||
|
UPDATE "group" SET description = 'The default group' WHERE id = 0;
|
||||||
|
|
||||||
|
DROP TRIGGER IF EXISTS tr_group_zero;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_group_zero AFTER DELETE ON "group"
|
||||||
|
BEGIN
|
||||||
|
INSERT OR IGNORE INTO "group" (id,enabled,name,description) VALUES (0,1,'Default','The default group');
|
||||||
|
END;
|
||||||
|
|
||||||
|
UPDATE info SET value = 12 WHERE property = 'version';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
18
advanced/Scripts/database_migration/gravity/12_to_13.sql
Normal file
18
advanced/Scripts/database_migration/gravity/12_to_13.sql
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
.timeout 30000
|
||||||
|
|
||||||
|
PRAGMA FOREIGN_KEYS=OFF;
|
||||||
|
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE adlist ADD COLUMN date_updated INTEGER;
|
||||||
|
|
||||||
|
DROP TRIGGER tr_adlist_update;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_adlist_update AFTER UPDATE OF address,enabled,comment ON adlist
|
||||||
|
BEGIN
|
||||||
|
UPDATE adlist SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE id = NEW.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
UPDATE info SET value = 13 WHERE property = 'version';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
13
advanced/Scripts/database_migration/gravity/13_to_14.sql
Normal file
13
advanced/Scripts/database_migration/gravity/13_to_14.sql
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
.timeout 30000
|
||||||
|
|
||||||
|
PRAGMA FOREIGN_KEYS=OFF;
|
||||||
|
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE adlist ADD COLUMN number INTEGER NOT NULL DEFAULT 0;
|
||||||
|
ALTER TABLE adlist ADD COLUMN invalid_domains INTEGER NOT NULL DEFAULT 0;
|
||||||
|
ALTER TABLE adlist ADD COLUMN status INTEGER NOT NULL DEFAULT 0;
|
||||||
|
|
||||||
|
UPDATE info SET value = 14 WHERE property = 'version';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
15
advanced/Scripts/database_migration/gravity/14_to_15.sql
Normal file
15
advanced/Scripts/database_migration/gravity/14_to_15.sql
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
.timeout 30000
|
||||||
|
|
||||||
|
PRAGMA FOREIGN_KEYS=OFF;
|
||||||
|
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
DROP VIEW vw_adlist;
|
||||||
|
|
||||||
|
CREATE VIEW vw_adlist AS SELECT DISTINCT address, id
|
||||||
|
FROM adlist
|
||||||
|
WHERE enabled = 1
|
||||||
|
ORDER BY id;
|
||||||
|
|
||||||
|
UPDATE info SET value = 15 WHERE property = 'version';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
14
advanced/Scripts/database_migration/gravity/1_to_2.sql
Normal file
14
advanced/Scripts/database_migration/gravity/1_to_2.sql
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
.timeout 30000
|
||||||
|
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
CREATE TABLE domain_audit
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
domain TEXT UNIQUE NOT NULL,
|
||||||
|
date_added INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int))
|
||||||
|
);
|
||||||
|
|
||||||
|
UPDATE info SET value = 2 WHERE property = 'version';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
65
advanced/Scripts/database_migration/gravity/2_to_3.sql
Normal file
65
advanced/Scripts/database_migration/gravity/2_to_3.sql
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
.timeout 30000
|
||||||
|
|
||||||
|
PRAGMA FOREIGN_KEYS=OFF;
|
||||||
|
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE regex RENAME TO regex_blacklist;
|
||||||
|
|
||||||
|
CREATE TABLE regex_blacklist_by_group
|
||||||
|
(
|
||||||
|
regex_blacklist_id INTEGER NOT NULL REFERENCES regex_blacklist (id),
|
||||||
|
group_id INTEGER NOT NULL REFERENCES "group" (id),
|
||||||
|
PRIMARY KEY (regex_blacklist_id, group_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO regex_blacklist_by_group SELECT * FROM regex_by_group;
|
||||||
|
DROP TABLE regex_by_group;
|
||||||
|
DROP VIEW vw_regex;
|
||||||
|
DROP TRIGGER tr_regex_update;
|
||||||
|
|
||||||
|
CREATE VIEW vw_regex_blacklist AS SELECT DISTINCT domain
|
||||||
|
FROM regex_blacklist
|
||||||
|
LEFT JOIN regex_blacklist_by_group ON regex_blacklist_by_group.regex_blacklist_id = regex_blacklist.id
|
||||||
|
LEFT JOIN "group" ON "group".id = regex_blacklist_by_group.group_id
|
||||||
|
WHERE regex_blacklist.enabled = 1 AND (regex_blacklist_by_group.group_id IS NULL OR "group".enabled = 1)
|
||||||
|
ORDER BY regex_blacklist.id;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_regex_blacklist_update AFTER UPDATE ON regex_blacklist
|
||||||
|
BEGIN
|
||||||
|
UPDATE regex_blacklist SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE domain = NEW.domain;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TABLE regex_whitelist
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
domain TEXT UNIQUE NOT NULL,
|
||||||
|
enabled BOOLEAN NOT NULL DEFAULT 1,
|
||||||
|
date_added INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||||
|
date_modified INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||||
|
comment TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE regex_whitelist_by_group
|
||||||
|
(
|
||||||
|
regex_whitelist_id INTEGER NOT NULL REFERENCES regex_whitelist (id),
|
||||||
|
group_id INTEGER NOT NULL REFERENCES "group" (id),
|
||||||
|
PRIMARY KEY (regex_whitelist_id, group_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE VIEW vw_regex_whitelist AS SELECT DISTINCT domain
|
||||||
|
FROM regex_whitelist
|
||||||
|
LEFT JOIN regex_whitelist_by_group ON regex_whitelist_by_group.regex_whitelist_id = regex_whitelist.id
|
||||||
|
LEFT JOIN "group" ON "group".id = regex_whitelist_by_group.group_id
|
||||||
|
WHERE regex_whitelist.enabled = 1 AND (regex_whitelist_by_group.group_id IS NULL OR "group".enabled = 1)
|
||||||
|
ORDER BY regex_whitelist.id;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_regex_whitelist_update AFTER UPDATE ON regex_whitelist
|
||||||
|
BEGIN
|
||||||
|
UPDATE regex_whitelist SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE domain = NEW.domain;
|
||||||
|
END;
|
||||||
|
|
||||||
|
|
||||||
|
UPDATE info SET value = 3 WHERE property = 'version';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
96
advanced/Scripts/database_migration/gravity/3_to_4.sql
Normal file
96
advanced/Scripts/database_migration/gravity/3_to_4.sql
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
.timeout 30000
|
||||||
|
|
||||||
|
PRAGMA FOREIGN_KEYS=OFF;
|
||||||
|
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
CREATE TABLE domainlist
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
type INTEGER NOT NULL DEFAULT 0,
|
||||||
|
domain TEXT UNIQUE NOT NULL,
|
||||||
|
enabled BOOLEAN NOT NULL DEFAULT 1,
|
||||||
|
date_added INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||||
|
date_modified INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||||
|
comment TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE whitelist ADD COLUMN type INTEGER;
|
||||||
|
UPDATE whitelist SET type = 0;
|
||||||
|
INSERT INTO domainlist (type,domain,enabled,date_added,date_modified,comment)
|
||||||
|
SELECT type,domain,enabled,date_added,date_modified,comment FROM whitelist;
|
||||||
|
|
||||||
|
ALTER TABLE blacklist ADD COLUMN type INTEGER;
|
||||||
|
UPDATE blacklist SET type = 1;
|
||||||
|
INSERT INTO domainlist (type,domain,enabled,date_added,date_modified,comment)
|
||||||
|
SELECT type,domain,enabled,date_added,date_modified,comment FROM blacklist;
|
||||||
|
|
||||||
|
ALTER TABLE regex_whitelist ADD COLUMN type INTEGER;
|
||||||
|
UPDATE regex_whitelist SET type = 2;
|
||||||
|
INSERT INTO domainlist (type,domain,enabled,date_added,date_modified,comment)
|
||||||
|
SELECT type,domain,enabled,date_added,date_modified,comment FROM regex_whitelist;
|
||||||
|
|
||||||
|
ALTER TABLE regex_blacklist ADD COLUMN type INTEGER;
|
||||||
|
UPDATE regex_blacklist SET type = 3;
|
||||||
|
INSERT INTO domainlist (type,domain,enabled,date_added,date_modified,comment)
|
||||||
|
SELECT type,domain,enabled,date_added,date_modified,comment FROM regex_blacklist;
|
||||||
|
|
||||||
|
DROP TABLE whitelist_by_group;
|
||||||
|
DROP TABLE blacklist_by_group;
|
||||||
|
DROP TABLE regex_whitelist_by_group;
|
||||||
|
DROP TABLE regex_blacklist_by_group;
|
||||||
|
CREATE TABLE domainlist_by_group
|
||||||
|
(
|
||||||
|
domainlist_id INTEGER NOT NULL REFERENCES domainlist (id),
|
||||||
|
group_id INTEGER NOT NULL REFERENCES "group" (id),
|
||||||
|
PRIMARY KEY (domainlist_id, group_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
DROP TRIGGER tr_whitelist_update;
|
||||||
|
DROP TRIGGER tr_blacklist_update;
|
||||||
|
DROP TRIGGER tr_regex_whitelist_update;
|
||||||
|
DROP TRIGGER tr_regex_blacklist_update;
|
||||||
|
CREATE TRIGGER tr_domainlist_update AFTER UPDATE ON domainlist
|
||||||
|
BEGIN
|
||||||
|
UPDATE domainlist SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE domain = NEW.domain;
|
||||||
|
END;
|
||||||
|
|
||||||
|
DROP VIEW vw_whitelist;
|
||||||
|
CREATE VIEW vw_whitelist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
||||||
|
FROM domainlist
|
||||||
|
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
||||||
|
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
||||||
|
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
||||||
|
AND domainlist.type = 0
|
||||||
|
ORDER BY domainlist.id;
|
||||||
|
|
||||||
|
DROP VIEW vw_blacklist;
|
||||||
|
CREATE VIEW vw_blacklist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
||||||
|
FROM domainlist
|
||||||
|
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
||||||
|
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
||||||
|
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
||||||
|
AND domainlist.type = 1
|
||||||
|
ORDER BY domainlist.id;
|
||||||
|
|
||||||
|
DROP VIEW vw_regex_whitelist;
|
||||||
|
CREATE VIEW vw_regex_whitelist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
||||||
|
FROM domainlist
|
||||||
|
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
||||||
|
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
||||||
|
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
||||||
|
AND domainlist.type = 2
|
||||||
|
ORDER BY domainlist.id;
|
||||||
|
|
||||||
|
DROP VIEW vw_regex_blacklist;
|
||||||
|
CREATE VIEW vw_regex_blacklist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
||||||
|
FROM domainlist
|
||||||
|
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
||||||
|
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
||||||
|
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
||||||
|
AND domainlist.type = 3
|
||||||
|
ORDER BY domainlist.id;
|
||||||
|
|
||||||
|
UPDATE info SET value = 4 WHERE property = 'version';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
38
advanced/Scripts/database_migration/gravity/4_to_5.sql
Normal file
38
advanced/Scripts/database_migration/gravity/4_to_5.sql
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
.timeout 30000
|
||||||
|
|
||||||
|
PRAGMA FOREIGN_KEYS=OFF;
|
||||||
|
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
DROP TABLE gravity;
|
||||||
|
CREATE TABLE gravity
|
||||||
|
(
|
||||||
|
domain TEXT NOT NULL,
|
||||||
|
adlist_id INTEGER NOT NULL REFERENCES adlist (id),
|
||||||
|
PRIMARY KEY(domain, adlist_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
DROP VIEW vw_gravity;
|
||||||
|
CREATE VIEW vw_gravity AS SELECT domain, adlist_by_group.group_id AS group_id
|
||||||
|
FROM gravity
|
||||||
|
LEFT JOIN adlist_by_group ON adlist_by_group.adlist_id = gravity.adlist_id
|
||||||
|
LEFT JOIN adlist ON adlist.id = gravity.adlist_id
|
||||||
|
LEFT JOIN "group" ON "group".id = adlist_by_group.group_id
|
||||||
|
WHERE adlist.enabled = 1 AND (adlist_by_group.group_id IS NULL OR "group".enabled = 1);
|
||||||
|
|
||||||
|
CREATE TABLE client
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
ip TEXT NOL NULL UNIQUE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE client_by_group
|
||||||
|
(
|
||||||
|
client_id INTEGER NOT NULL REFERENCES client (id),
|
||||||
|
group_id INTEGER NOT NULL REFERENCES "group" (id),
|
||||||
|
PRIMARY KEY (client_id, group_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
UPDATE info SET value = 5 WHERE property = 'version';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
18
advanced/Scripts/database_migration/gravity/5_to_6.sql
Normal file
18
advanced/Scripts/database_migration/gravity/5_to_6.sql
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
.timeout 30000
|
||||||
|
|
||||||
|
PRAGMA FOREIGN_KEYS=OFF;
|
||||||
|
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
DROP VIEW vw_adlist;
|
||||||
|
CREATE VIEW vw_adlist AS SELECT DISTINCT address, adlist.id AS id
|
||||||
|
FROM adlist
|
||||||
|
LEFT JOIN adlist_by_group ON adlist_by_group.adlist_id = adlist.id
|
||||||
|
LEFT JOIN "group" ON "group".id = adlist_by_group.group_id
|
||||||
|
WHERE adlist.enabled = 1 AND (adlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
||||||
|
ORDER BY adlist.id;
|
||||||
|
|
||||||
|
UPDATE info SET value = 6 WHERE property = 'version';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
35
advanced/Scripts/database_migration/gravity/6_to_7.sql
Normal file
35
advanced/Scripts/database_migration/gravity/6_to_7.sql
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
.timeout 30000
|
||||||
|
|
||||||
|
PRAGMA FOREIGN_KEYS=OFF;
|
||||||
|
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
INSERT OR REPLACE INTO "group" (id,enabled,name) VALUES (0,1,'Unassociated');
|
||||||
|
|
||||||
|
INSERT INTO domainlist_by_group (domainlist_id, group_id) SELECT id, 0 FROM domainlist;
|
||||||
|
INSERT INTO client_by_group (client_id, group_id) SELECT id, 0 FROM client;
|
||||||
|
INSERT INTO adlist_by_group (adlist_id, group_id) SELECT id, 0 FROM adlist;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_domainlist_add AFTER INSERT ON domainlist
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO domainlist_by_group (domainlist_id, group_id) VALUES (NEW.id, 0);
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_client_add AFTER INSERT ON client
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO client_by_group (client_id, group_id) VALUES (NEW.id, 0);
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_adlist_add AFTER INSERT ON adlist
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO adlist_by_group (adlist_id, group_id) VALUES (NEW.id, 0);
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_group_zero AFTER DELETE ON "group"
|
||||||
|
BEGIN
|
||||||
|
INSERT OR REPLACE INTO "group" (id,enabled,name) VALUES (0,1,'Unassociated');
|
||||||
|
END;
|
||||||
|
|
||||||
|
UPDATE info SET value = 7 WHERE property = 'version';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
35
advanced/Scripts/database_migration/gravity/7_to_8.sql
Normal file
35
advanced/Scripts/database_migration/gravity/7_to_8.sql
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
.timeout 30000
|
||||||
|
|
||||||
|
PRAGMA FOREIGN_KEYS=OFF;
|
||||||
|
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE "group" RENAME TO "group__";
|
||||||
|
|
||||||
|
CREATE TABLE "group"
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
enabled BOOLEAN NOT NULL DEFAULT 1,
|
||||||
|
name TEXT UNIQUE NOT NULL,
|
||||||
|
date_added INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||||
|
date_modified INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||||
|
description TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_group_update AFTER UPDATE ON "group"
|
||||||
|
BEGIN
|
||||||
|
UPDATE "group" SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE id = NEW.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
INSERT OR IGNORE INTO "group" (id,enabled,name,description) SELECT id,enabled,name,description FROM "group__";
|
||||||
|
|
||||||
|
DROP TABLE "group__";
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_group_zero AFTER DELETE ON "group"
|
||||||
|
BEGIN
|
||||||
|
INSERT OR IGNORE INTO "group" (id,enabled,name) VALUES (0,1,'Unassociated');
|
||||||
|
END;
|
||||||
|
|
||||||
|
UPDATE info SET value = 8 WHERE property = 'version';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
27
advanced/Scripts/database_migration/gravity/8_to_9.sql
Normal file
27
advanced/Scripts/database_migration/gravity/8_to_9.sql
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
.timeout 30000
|
||||||
|
|
||||||
|
PRAGMA FOREIGN_KEYS=OFF;
|
||||||
|
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
DROP TRIGGER IF EXISTS tr_group_update;
|
||||||
|
DROP TRIGGER IF EXISTS tr_group_zero;
|
||||||
|
|
||||||
|
PRAGMA legacy_alter_table=ON;
|
||||||
|
ALTER TABLE "group" RENAME TO "group__";
|
||||||
|
PRAGMA legacy_alter_table=OFF;
|
||||||
|
ALTER TABLE "group__" RENAME TO "group";
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_group_update AFTER UPDATE ON "group"
|
||||||
|
BEGIN
|
||||||
|
UPDATE "group" SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE id = NEW.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_group_zero AFTER DELETE ON "group"
|
||||||
|
BEGIN
|
||||||
|
INSERT OR IGNORE INTO "group" (id,enabled,name) VALUES (0,1,'Unassociated');
|
||||||
|
END;
|
||||||
|
|
||||||
|
UPDATE info SET value = 9 WHERE property = 'version';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
29
advanced/Scripts/database_migration/gravity/9_to_10.sql
Normal file
29
advanced/Scripts/database_migration/gravity/9_to_10.sql
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
.timeout 30000
|
||||||
|
|
||||||
|
PRAGMA FOREIGN_KEYS=OFF;
|
||||||
|
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS whitelist;
|
||||||
|
DROP TABLE IF EXISTS blacklist;
|
||||||
|
DROP TABLE IF EXISTS regex_whitelist;
|
||||||
|
DROP TABLE IF EXISTS regex_blacklist;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_domainlist_delete AFTER DELETE ON domainlist
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM domainlist_by_group WHERE domainlist_id = OLD.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_adlist_delete AFTER DELETE ON adlist
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM adlist_by_group WHERE adlist_id = OLD.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_client_delete AFTER DELETE ON client
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM client_by_group WHERE client_id = OLD.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
UPDATE info SET value = 10 WHERE property = 'version';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
301
advanced/Scripts/list.sh
Executable file
301
advanced/Scripts/list.sh
Executable file
@@ -0,0 +1,301 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
|
||||||
|
# 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
|
||||||
|
piholeDir="/etc/pihole"
|
||||||
|
GRAVITYDB="${piholeDir}/gravity.db"
|
||||||
|
# Source pihole-FTL from install script
|
||||||
|
pihole_FTL="${piholeDir}/pihole-FTL.conf"
|
||||||
|
if [[ -f "${pihole_FTL}" ]]; then
|
||||||
|
source "${pihole_FTL}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set this only after sourcing pihole-FTL.conf as the gravity database path may
|
||||||
|
# have changed
|
||||||
|
gravityDBfile="${GRAVITYDB}"
|
||||||
|
|
||||||
|
noReloadRequested=false
|
||||||
|
addmode=true
|
||||||
|
verbose=true
|
||||||
|
wildcard=false
|
||||||
|
web=false
|
||||||
|
|
||||||
|
domList=()
|
||||||
|
|
||||||
|
typeId=""
|
||||||
|
comment=""
|
||||||
|
declare -i domaincount
|
||||||
|
domaincount=0
|
||||||
|
reload=false
|
||||||
|
|
||||||
|
colfile="/opt/pihole/COL_TABLE"
|
||||||
|
source ${colfile}
|
||||||
|
|
||||||
|
# IDs are hard-wired to domain interpretation in the gravity database scheme
|
||||||
|
# Clients (including FTL) will read them through the corresponding views
|
||||||
|
readonly whitelist="0"
|
||||||
|
readonly blacklist="1"
|
||||||
|
readonly regex_whitelist="2"
|
||||||
|
readonly regex_blacklist="3"
|
||||||
|
|
||||||
|
GetListnameFromTypeId() {
|
||||||
|
if [[ "$1" == "${whitelist}" ]]; then
|
||||||
|
echo "whitelist"
|
||||||
|
elif [[ "$1" == "${blacklist}" ]]; then
|
||||||
|
echo "blacklist"
|
||||||
|
elif [[ "$1" == "${regex_whitelist}" ]]; then
|
||||||
|
echo "regex whitelist"
|
||||||
|
elif [[ "$1" == "${regex_blacklist}" ]]; then
|
||||||
|
echo "regex blacklist"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
GetListParamFromTypeId() {
|
||||||
|
if [[ "${typeId}" == "${whitelist}" ]]; then
|
||||||
|
echo "w"
|
||||||
|
elif [[ "${typeId}" == "${blacklist}" ]]; then
|
||||||
|
echo "b"
|
||||||
|
elif [[ "${typeId}" == "${regex_whitelist}" && "${wildcard}" == true ]]; then
|
||||||
|
echo "-white-wild"
|
||||||
|
elif [[ "${typeId}" == "${regex_whitelist}" ]]; then
|
||||||
|
echo "-white-regex"
|
||||||
|
elif [[ "${typeId}" == "${regex_blacklist}" && "${wildcard}" == true ]]; then
|
||||||
|
echo "-wild"
|
||||||
|
elif [[ "${typeId}" == "${regex_blacklist}" ]]; then
|
||||||
|
echo "-regex"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
helpFunc() {
|
||||||
|
local listname param
|
||||||
|
|
||||||
|
listname="$(GetListnameFromTypeId "${typeId}")"
|
||||||
|
param="$(GetListParamFromTypeId)"
|
||||||
|
|
||||||
|
echo "Usage: pihole -${param} [options] <domain> <domain2 ...>
|
||||||
|
Example: 'pihole -${param} site.com', or 'pihole -${param} site1.com site2.com'
|
||||||
|
${listname^} one or more domains
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-d, --delmode Remove domain(s) from the ${listname}
|
||||||
|
-nr, --noreload Update ${listname} without reloading the DNS server
|
||||||
|
-q, --quiet Make output less verbose
|
||||||
|
-h, --help Show this help dialog
|
||||||
|
-l, --list Display all your ${listname}listed domains
|
||||||
|
--nuke Removes all entries in a list
|
||||||
|
--comment \"text\" Add a comment to the domain. If adding multiple domains the same comment will be used for all"
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidateDomain() {
|
||||||
|
# Convert to lowercase
|
||||||
|
domain="${1,,}"
|
||||||
|
|
||||||
|
# Check validity of domain (don't check for regex entries)
|
||||||
|
if [[ "${#domain}" -le 253 ]]; then
|
||||||
|
if [[ ( "${typeId}" == "${regex_blacklist}" || "${typeId}" == "${regex_whitelist}" ) && "${wildcard}" == false ]]; then
|
||||||
|
validDomain="${domain}"
|
||||||
|
else
|
||||||
|
validDomain=$(grep -P "^((-|_)*[a-z\\d]((-|_)*[a-z\\d])*(-|_)*)(\\.(-|_)*([a-z\\d]((-|_)*[a-z\\d])*))*$" <<< "${domain}") # Valid chars check
|
||||||
|
validDomain=$(grep -P "^[^\\.]{1,63}(\\.[^\\.]{1,63})*$" <<< "${validDomain}") # Length of each label
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "${validDomain}" ]]; then
|
||||||
|
domList=("${domList[@]}" "${validDomain}")
|
||||||
|
else
|
||||||
|
echo -e " ${CROSS} ${domain} is not a valid argument or domain name!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
domaincount=$((domaincount+1))
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessDomainList() {
|
||||||
|
for dom in "${domList[@]}"; do
|
||||||
|
# Format domain into regex filter if requested
|
||||||
|
if [[ "${wildcard}" == true ]]; then
|
||||||
|
dom="(\\.|^)${dom//\./\\.}$"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 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}"
|
||||||
|
else
|
||||||
|
RemoveDomain "${dom}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
AddDomain() {
|
||||||
|
local domain num requestedListname existingTypeId existingListname
|
||||||
|
domain="$1"
|
||||||
|
|
||||||
|
# Is the domain in the list we want to add it to?
|
||||||
|
num="$(sqlite3 "${gravityDBfile}" "SELECT COUNT(*) FROM domainlist WHERE domain = '${domain}';")"
|
||||||
|
requestedListname="$(GetListnameFromTypeId "${typeId}")"
|
||||||
|
|
||||||
|
if [[ "${num}" -ne 0 ]]; then
|
||||||
|
existingTypeId="$(sqlite3 "${gravityDBfile}" "SELECT type FROM domainlist WHERE domain = '${domain}';")"
|
||||||
|
if [[ "${existingTypeId}" == "${typeId}" ]]; then
|
||||||
|
if [[ "${verbose}" == true ]]; then
|
||||||
|
echo -e " ${INFO} ${1} already exists in ${requestedListname}, no need to add!"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
existingListname="$(GetListnameFromTypeId "${existingTypeId}")"
|
||||||
|
sqlite3 "${gravityDBfile}" "UPDATE domainlist SET type = ${typeId} WHERE domain='${domain}';"
|
||||||
|
if [[ "${verbose}" == true ]]; then
|
||||||
|
echo -e " ${INFO} ${1} already exists in ${existingListname}, it has been moved to ${requestedListname}!"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Domain not found in the table, add it!
|
||||||
|
if [[ "${verbose}" == true ]]; then
|
||||||
|
echo -e " ${INFO} Adding ${domain} to the ${requestedListname}..."
|
||||||
|
fi
|
||||||
|
reload=true
|
||||||
|
# Insert only the domain here. The enabled and date_added fields will be filled
|
||||||
|
# with their default values (enabled = true, date_added = current timestamp)
|
||||||
|
if [[ -z "${comment}" ]]; then
|
||||||
|
sqlite3 "${gravityDBfile}" "INSERT INTO domainlist (domain,type) VALUES ('${domain}',${typeId});"
|
||||||
|
else
|
||||||
|
# also add comment when variable has been set through the "--comment" option
|
||||||
|
sqlite3 "${gravityDBfile}" "INSERT INTO domainlist (domain,type,comment) VALUES ('${domain}',${typeId},'${comment}');"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveDomain() {
|
||||||
|
local domain num requestedListname
|
||||||
|
domain="$1"
|
||||||
|
|
||||||
|
# Is the domain in the list we want to remove it from?
|
||||||
|
num="$(sqlite3 "${gravityDBfile}" "SELECT COUNT(*) FROM domainlist WHERE domain = '${domain}' AND type = ${typeId};")"
|
||||||
|
|
||||||
|
requestedListname="$(GetListnameFromTypeId "${typeId}")"
|
||||||
|
|
||||||
|
if [[ "${num}" -eq 0 ]]; then
|
||||||
|
if [[ "${verbose}" == true ]]; then
|
||||||
|
echo -e " ${INFO} ${domain} does not exist in ${requestedListname}, no need to remove!"
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Domain found in the table, remove it!
|
||||||
|
if [[ "${verbose}" == true ]]; then
|
||||||
|
echo -e " ${INFO} Removing ${domain} from the ${requestedListname}..."
|
||||||
|
fi
|
||||||
|
reload=true
|
||||||
|
# Remove it from the current list
|
||||||
|
sqlite3 "${gravityDBfile}" "DELETE FROM domainlist WHERE domain = '${domain}' AND type = ${typeId};"
|
||||||
|
}
|
||||||
|
|
||||||
|
Displaylist() {
|
||||||
|
local count num_pipes domain enabled status nicedate requestedListname
|
||||||
|
|
||||||
|
requestedListname="$(GetListnameFromTypeId "${typeId}")"
|
||||||
|
data="$(sqlite3 "${gravityDBfile}" "SELECT domain,enabled,date_modified FROM domainlist WHERE type = ${typeId};" 2> /dev/null)"
|
||||||
|
|
||||||
|
if [[ -z $data ]]; then
|
||||||
|
echo -e "Not showing empty list"
|
||||||
|
else
|
||||||
|
echo -e "Displaying ${requestedListname}:"
|
||||||
|
count=1
|
||||||
|
while IFS= read -r line
|
||||||
|
do
|
||||||
|
# Count number of pipes seen in this line
|
||||||
|
# This is necessary because we can only detect the pipe separating the fields
|
||||||
|
# from the end backwards as the domain (which is the first field) may contain
|
||||||
|
# pipe symbols as they are perfectly valid regex filter control characters
|
||||||
|
num_pipes="$(grep -c "^" <<< "$(grep -o "|" <<< "${line}")")"
|
||||||
|
|
||||||
|
# Extract domain and enabled status based on the obtained number of pipe characters
|
||||||
|
domain="$(cut -d'|' -f"-$((num_pipes-1))" <<< "${line}")"
|
||||||
|
enabled="$(cut -d'|' -f"$((num_pipes))" <<< "${line}")"
|
||||||
|
datemod="$(cut -d'|' -f"$((num_pipes+1))" <<< "${line}")"
|
||||||
|
|
||||||
|
# Translate boolean status into human readable string
|
||||||
|
if [[ "${enabled}" -eq 1 ]]; then
|
||||||
|
status="enabled"
|
||||||
|
else
|
||||||
|
status="disabled"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get nice representation of numerical date stored in database
|
||||||
|
nicedate=$(date --rfc-2822 -d "@${datemod}")
|
||||||
|
|
||||||
|
echo " ${count}: ${domain} (${status}, last modified ${nicedate})"
|
||||||
|
count=$((count+1))
|
||||||
|
done <<< "${data}"
|
||||||
|
fi
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NukeList() {
|
||||||
|
count=$(sqlite3 "${gravityDBfile}" "SELECT COUNT(1) FROM domainlist WHERE type = ${typeId};")
|
||||||
|
listname="$(GetListnameFromTypeId "${typeId}")"
|
||||||
|
if [ "$count" -gt 0 ];then
|
||||||
|
sqlite3 "${gravityDBfile}" "DELETE FROM domainlist WHERE type = ${typeId};"
|
||||||
|
echo " ${TICK} Removed ${count} domain(s) from the ${listname}"
|
||||||
|
else
|
||||||
|
echo " ${INFO} ${listname} already empty. Nothing to do!"
|
||||||
|
fi
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetComment() {
|
||||||
|
comment="$1"
|
||||||
|
if [[ "${comment}" =~ [^a-zA-Z0-9_\#:/\.,\ -] ]]; then
|
||||||
|
echo " ${CROSS} Found invalid characters in domain comment!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
while (( "$#" )); do
|
||||||
|
case "${1}" in
|
||||||
|
"-w" | "whitelist" ) typeId=0;;
|
||||||
|
"-b" | "blacklist" ) typeId=1;;
|
||||||
|
"--white-regex" | "white-regex" ) typeId=2;;
|
||||||
|
"--white-wild" | "white-wild" ) typeId=2; wildcard=true;;
|
||||||
|
"--wild" | "wildcard" ) typeId=3; wildcard=true;;
|
||||||
|
"--regex" | "regex" ) typeId=3;;
|
||||||
|
"-nr"| "--noreload" ) noReloadRequested=true;;
|
||||||
|
"-d" | "--delmode" ) addmode=false;;
|
||||||
|
"-q" | "--quiet" ) verbose=false;;
|
||||||
|
"-h" | "--help" ) helpFunc;;
|
||||||
|
"-l" | "--list" ) Displaylist;;
|
||||||
|
"--nuke" ) NukeList;;
|
||||||
|
"--web" ) web=true;;
|
||||||
|
"--comment" ) GetComment "${2}"; shift;;
|
||||||
|
* ) ValidateDomain "${1}";;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
shift
|
||||||
|
|
||||||
|
if [[ ${domaincount} == 0 ]]; then
|
||||||
|
helpFunc
|
||||||
|
fi
|
||||||
|
|
||||||
|
ProcessDomainList
|
||||||
|
|
||||||
|
# Used on web interface
|
||||||
|
if $web; then
|
||||||
|
echo "DONE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${reload} == true && ${noReloadRequested} == false ]]; then
|
||||||
|
pihole restartdns reload-lists
|
||||||
|
fi
|
||||||
23
advanced/Scripts/pihole-reenable.sh
Executable file
23
advanced/Scripts/pihole-reenable.sh
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Pi-hole: A black hole for Internet advertisements
|
||||||
|
# (c) 2020 Pi-hole, LLC (https://pi-hole.net)
|
||||||
|
# Network-wide ad blocking via your own hardware.
|
||||||
|
#
|
||||||
|
# This file is copyright under the latest version of the EUPL.
|
||||||
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# The pihole disable command has the option to set a specified time before
|
||||||
|
# blocking is automatically re-enabled.
|
||||||
|
#
|
||||||
|
# Present script is responsible for the sleep & re-enable part of the job and
|
||||||
|
# is automatically terminated if it is still running when pihole is enabled by
|
||||||
|
# other means.
|
||||||
|
#
|
||||||
|
# This ensures that pihole ends up in the correct state after a sequence of
|
||||||
|
# commands suchs as: `pihole disable 30s; pihole enable; pihole disable`
|
||||||
|
|
||||||
|
readonly PI_HOLE_BIN_DIR="/usr/local/bin"
|
||||||
|
|
||||||
|
sleep "${1}"
|
||||||
|
"${PI_HOLE_BIN_DIR}"/pihole enable
|
||||||
66
advanced/Scripts/piholeARPTable.sh
Executable file
66
advanced/Scripts/piholeARPTable.sh
Executable file
@@ -0,0 +1,66 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
|
||||||
|
# Pi-hole: A black hole for Internet advertisements
|
||||||
|
# (c) 2019 Pi-hole, LLC (https://pi-hole.net)
|
||||||
|
# Network-wide ad blocking via your own hardware.
|
||||||
|
#
|
||||||
|
# ARP table interaction
|
||||||
|
#
|
||||||
|
# This file is copyright under the latest version of the EUPL.
|
||||||
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
|
coltable="/opt/pihole/COL_TABLE"
|
||||||
|
if [[ -f ${coltable} ]]; then
|
||||||
|
source ${coltable}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine database location
|
||||||
|
# Obtain DBFILE=... setting from pihole-FTL.db
|
||||||
|
# Constructed to return nothing when
|
||||||
|
# a) the setting is not present in the config file, or
|
||||||
|
# b) the setting is commented out (e.g. "#DBFILE=...")
|
||||||
|
FTLconf="/etc/pihole/pihole-FTL.conf"
|
||||||
|
if [ -e "$FTLconf" ]; then
|
||||||
|
DBFILE="$(sed -n -e 's/^\s*DBFILE\s*=\s*//p' ${FTLconf})"
|
||||||
|
fi
|
||||||
|
# Test for empty string. Use standard path in this case.
|
||||||
|
if [ -z "$DBFILE" ]; then
|
||||||
|
DBFILE="/etc/pihole/pihole-FTL.db"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
flushARP(){
|
||||||
|
local output
|
||||||
|
if [[ "${args[1]}" != "quiet" ]]; then
|
||||||
|
echo -ne " ${INFO} Flushing network table ..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Truncate network_addresses table in pihole-FTL.db
|
||||||
|
# This needs to be done before we can truncate the network table due to
|
||||||
|
# foreign key constraints
|
||||||
|
if ! output=$(sqlite3 "${DBFILE}" "DELETE FROM network_addresses" 2>&1); then
|
||||||
|
echo -e "${OVER} ${CROSS} Failed to truncate network_addresses table"
|
||||||
|
echo " Database location: ${DBFILE}"
|
||||||
|
echo " Output: ${output}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Truncate network table in pihole-FTL.db
|
||||||
|
if ! output=$(sqlite3 "${DBFILE}" "DELETE FROM network" 2>&1); then
|
||||||
|
echo -e "${OVER} ${CROSS} Failed to truncate network table"
|
||||||
|
echo " Database location: ${DBFILE}"
|
||||||
|
echo " Output: ${output}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${args[1]}" != "quiet" ]]; then
|
||||||
|
echo -e "${OVER} ${TICK} Flushed network table"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
args=("$@")
|
||||||
|
|
||||||
|
case "${args[0]}" in
|
||||||
|
"arpflush" ) flushARP;;
|
||||||
|
esac
|
||||||
204
advanced/Scripts/piholeCheckout.sh
Executable file
204
advanced/Scripts/piholeCheckout.sh
Executable file
@@ -0,0 +1,204 @@
|
|||||||
|
#!/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
|
||||||
|
# check_download_exists sourced from basic-install.sh
|
||||||
|
# fully_fetch_repo sourced from basic-install.sh
|
||||||
|
# get_available_branches sourced from basic-install.sh
|
||||||
|
# fetch_checkout_pull_branch sourced from basic-install.sh
|
||||||
|
# checkout_pull_branch sourced from basic-install.sh
|
||||||
|
|
||||||
|
source "${setupVars}"
|
||||||
|
|
||||||
|
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 " ${COL_LIGHT_RED}This feature is NOT supported unless a Pi-hole developer explicitly asks!${COL_NC}"
|
||||||
|
read -r -p " Have you read and understood this? [y/N] " response
|
||||||
|
case "${response}" in
|
||||||
|
[yY][eE][sS]|[yY])
|
||||||
|
echo ""
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e "\\n ${INFO} Branch change has been canceled"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
checkout() {
|
||||||
|
local corebranches
|
||||||
|
local webbranches
|
||||||
|
|
||||||
|
# Check if FTL is installed - do this early on as FTL is a hard dependency for Pi-hole
|
||||||
|
local funcOutput
|
||||||
|
funcOutput=$(get_binary_name) #Store output of get_binary_name here
|
||||||
|
local binary
|
||||||
|
binary="pihole-FTL${funcOutput##*pihole-FTL}" #binary name will be the last line of the output of get_binary_name (it always begins with pihole-FTL)
|
||||||
|
|
||||||
|
# Avoid globbing
|
||||||
|
set -f
|
||||||
|
|
||||||
|
# This is unlikely
|
||||||
|
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
|
||||||
|
echo -e " ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!"
|
||||||
|
echo -e " Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}"
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
if [[ "${INSTALL_WEB_INTERFACE}" == "true" ]]; then
|
||||||
|
if ! is_repo "${webInterfaceDir}" ; then
|
||||||
|
echo -e " ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!"
|
||||||
|
echo -e " Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}"
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "${1}" ]]; then
|
||||||
|
echo -e " ${COL_LIGHT_RED}Invalid option${COL_NC}"
|
||||||
|
echo -e " Try 'pihole checkout --help' for more information."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! warning1 ; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${1}" == "dev" ]] ; then
|
||||||
|
# Shortcut to check out development branches
|
||||||
|
echo -e " ${INFO} Shortcut \"dev\" detected - checking out development / devel branches..."
|
||||||
|
echo ""
|
||||||
|
echo -e " ${INFO} Pi-hole Core"
|
||||||
|
fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "development" || { echo " ${CROSS} Unable to pull Core development branch"; exit 1; }
|
||||||
|
if [[ "${INSTALL_WEB_INTERFACE}" == "true" ]]; then
|
||||||
|
echo ""
|
||||||
|
echo -e " ${INFO} Web interface"
|
||||||
|
fetch_checkout_pull_branch "${webInterfaceDir}" "devel" || { echo " ${CROSS} Unable to pull Web development branch"; exit 1; }
|
||||||
|
fi
|
||||||
|
#echo -e " ${TICK} Pi-hole Core"
|
||||||
|
|
||||||
|
local path
|
||||||
|
path="development/${binary}"
|
||||||
|
echo "development" > /etc/pihole/ftlbranch
|
||||||
|
chmod 644 /etc/pihole/ftlbranch
|
||||||
|
elif [[ "${1}" == "master" ]] ; then
|
||||||
|
# Shortcut to check out master branches
|
||||||
|
echo -e " ${INFO} Shortcut \"master\" detected - checking out master branches..."
|
||||||
|
echo -e " ${INFO} Pi-hole core"
|
||||||
|
fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "master" || { echo " ${CROSS} Unable to pull Core master branch"; exit 1; }
|
||||||
|
if [[ ${INSTALL_WEB_INTERFACE} == "true" ]]; then
|
||||||
|
echo -e " ${INFO} Web interface"
|
||||||
|
fetch_checkout_pull_branch "${webInterfaceDir}" "master" || { echo " ${CROSS} Unable to pull Web master branch"; exit 1; }
|
||||||
|
fi
|
||||||
|
#echo -e " ${TICK} Web Interface"
|
||||||
|
local path
|
||||||
|
path="master/${binary}"
|
||||||
|
echo "master" > /etc/pihole/ftlbranch
|
||||||
|
chmod 644 /etc/pihole/ftlbranch
|
||||||
|
elif [[ "${1}" == "core" ]] ; then
|
||||||
|
str="Fetching branches from ${piholeGitUrl}"
|
||||||
|
echo -ne " ${INFO} $str"
|
||||||
|
if ! fully_fetch_repo "${PI_HOLE_FILES_DIR}" ; then
|
||||||
|
echo -e "${OVER} ${CROSS} $str"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
corebranches=($(get_available_branches "${PI_HOLE_FILES_DIR}"))
|
||||||
|
|
||||||
|
if [[ "${corebranches[*]}" == *"master"* ]]; then
|
||||||
|
echo -e "${OVER} ${TICK} $str"
|
||||||
|
echo -e " ${INFO} ${#corebranches[@]} branches available for Pi-hole Core"
|
||||||
|
else
|
||||||
|
# Print STDERR output from get_available_branches
|
||||||
|
echo -e "${OVER} ${CROSS} $str\\n\\n${corebranches[*]}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
# Have the user choose the branch they want
|
||||||
|
if ! (for e in "${corebranches[@]}"; do [[ "$e" == "${2}" ]] && exit 0; done); then
|
||||||
|
echo -e " ${INFO} Requested branch \"${2}\" is not available"
|
||||||
|
echo -e " ${INFO} 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_INTERFACE}" == "true" ]] ; then
|
||||||
|
str="Fetching branches from ${webInterfaceGitUrl}"
|
||||||
|
echo -ne " ${INFO} $str"
|
||||||
|
if ! fully_fetch_repo "${webInterfaceDir}" ; then
|
||||||
|
echo -e "${OVER} ${CROSS} $str"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
webbranches=($(get_available_branches "${webInterfaceDir}"))
|
||||||
|
|
||||||
|
if [[ "${webbranches[*]}" == *"master"* ]]; then
|
||||||
|
echo -e "${OVER} ${TICK} $str"
|
||||||
|
echo -e " ${INFO} ${#webbranches[@]} branches available for Web Admin"
|
||||||
|
else
|
||||||
|
# Print STDERR output from get_available_branches
|
||||||
|
echo -e "${OVER} ${CROSS} $str\\n\\n${webbranches[*]}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
# Have the user choose the branch they want
|
||||||
|
if ! (for e in "${webbranches[@]}"; do [[ "$e" == "${2}" ]] && exit 0; done); then
|
||||||
|
echo -e " ${INFO} Requested branch \"${2}\" is not available"
|
||||||
|
echo -e " ${INFO} Available branches for Web Admin are:"
|
||||||
|
for e in "${webbranches[@]}"; do echo " - $e"; done
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
checkout_pull_branch "${webInterfaceDir}" "${2}"
|
||||||
|
elif [[ "${1}" == "ftl" ]] ; then
|
||||||
|
local path
|
||||||
|
local oldbranch
|
||||||
|
path="${2}/${binary}"
|
||||||
|
oldbranch="$(pihole-FTL -b)"
|
||||||
|
|
||||||
|
if check_download_exists "$path"; then
|
||||||
|
echo " ${TICK} Branch ${2} exists"
|
||||||
|
echo "${2}" > /etc/pihole/ftlbranch
|
||||||
|
chmod 644 /etc/pihole/ftlbranch
|
||||||
|
echo -e " ${INFO} Switching to branch: \"${2}\" from \"${oldbranch}\""
|
||||||
|
FTLinstall "${binary}"
|
||||||
|
restart_service pihole-FTL
|
||||||
|
enable_service pihole-FTL
|
||||||
|
else
|
||||||
|
echo " ${CROSS} Requested branch \"${2}\" is not available"
|
||||||
|
ftlbranches=( $(git ls-remote https://github.com/pi-hole/ftl | grep 'heads' | sed 's/refs\/heads\///;s/ //g' | awk '{print $2}') )
|
||||||
|
echo -e " ${INFO} Available branches for FTL are:"
|
||||||
|
for e in "${ftlbranches[@]}"; do echo " - $e"; done
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
else
|
||||||
|
echo -e " ${INFO} Requested option \"${1}\" is not available"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Force updating everything
|
||||||
|
if [[ ! "${1}" == "web" && ! "${1}" == "ftl" ]]; then
|
||||||
|
echo -e " ${INFO} Running installer to upgrade your installation"
|
||||||
|
if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo -e " ${COL_LIGHT_RED} Error: Unable to complete update, please contact support${COL_NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
1472
advanced/Scripts/piholeDebug.sh
Executable file
1472
advanced/Scripts/piholeDebug.sh
Executable file
File diff suppressed because it is too large
Load Diff
75
advanced/Scripts/piholeLogFlush.sh
Executable file
75
advanced/Scripts/piholeLogFlush.sh
Executable file
@@ -0,0 +1,75 @@
|
|||||||
|
#!/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.
|
||||||
|
|
||||||
|
colfile="/opt/pihole/COL_TABLE"
|
||||||
|
source ${colfile}
|
||||||
|
|
||||||
|
# In case we're running at the same time as a system logrotate, use a
|
||||||
|
# separate logrotate state file to prevent stepping on each other's
|
||||||
|
# toes.
|
||||||
|
STATEFILE="/var/lib/logrotate/pihole"
|
||||||
|
|
||||||
|
# Determine database location
|
||||||
|
# Obtain DBFILE=... setting from pihole-FTL.db
|
||||||
|
# Constructed to return nothing when
|
||||||
|
# a) the setting is not present in the config file, or
|
||||||
|
# b) the setting is commented out (e.g. "#DBFILE=...")
|
||||||
|
FTLconf="/etc/pihole/pihole-FTL.conf"
|
||||||
|
if [ -e "$FTLconf" ]; then
|
||||||
|
DBFILE="$(sed -n -e 's/^\s*DBFILE\s*=\s*//p' ${FTLconf})"
|
||||||
|
fi
|
||||||
|
# Test for empty string. Use standard path in this case.
|
||||||
|
if [ -z "$DBFILE" ]; then
|
||||||
|
DBFILE="/etc/pihole/pihole-FTL.db"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$@" != *"quiet"* ]]; then
|
||||||
|
echo -ne " ${INFO} 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 --state "${STATEFILE}" /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 -p /var/log/pihole.log /var/log/pihole.log.1
|
||||||
|
echo " " > /var/log/pihole.log
|
||||||
|
chmod 644 /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 --state "${STATEFILE}" /etc/pihole/logrotate; sleep 3
|
||||||
|
/usr/sbin/logrotate --force --state "${STATEFILE}" /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
|
||||||
|
chmod 644 /var/log/pihole.log.1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
# Delete most recent 24 hours from FTL's database, leave even older data intact (don't wipe out all history)
|
||||||
|
deleted=$(sqlite3 "${DBFILE}" "DELETE FROM queries WHERE timestamp >= strftime('%s','now')-86400; select changes() from queries limit 1")
|
||||||
|
|
||||||
|
# Restart pihole-FTL to force reloading history
|
||||||
|
sudo pihole restartdns
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$@" != *"quiet"* ]]; then
|
||||||
|
echo -e "${OVER} ${TICK} Flushed /var/log/pihole.log"
|
||||||
|
echo -e " ${TICK} Deleted ${deleted} queries from database"
|
||||||
|
fi
|
||||||
264
advanced/Scripts/query.sh
Executable file
264
advanced/Scripts/query.sh
Executable file
@@ -0,0 +1,264 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
|
||||||
|
# Pi-hole: A black hole for Internet advertisements
|
||||||
|
# (c) 2018 Pi-hole, LLC (https://pi-hole.net)
|
||||||
|
# Network-wide ad blocking via your own hardware.
|
||||||
|
#
|
||||||
|
# Query Domain Lists
|
||||||
|
#
|
||||||
|
# This file is copyright under the latest version of the EUPL.
|
||||||
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
|
# Globals
|
||||||
|
piholeDir="/etc/pihole"
|
||||||
|
GRAVITYDB="${piholeDir}/gravity.db"
|
||||||
|
options="$*"
|
||||||
|
all=""
|
||||||
|
exact=""
|
||||||
|
blockpage=""
|
||||||
|
matchType="match"
|
||||||
|
# Source pihole-FTL from install script
|
||||||
|
pihole_FTL="${piholeDir}/pihole-FTL.conf"
|
||||||
|
if [[ -f "${pihole_FTL}" ]]; then
|
||||||
|
source "${pihole_FTL}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set this only after sourcing pihole-FTL.conf as the gravity database path may
|
||||||
|
# have changed
|
||||||
|
gravityDBfile="${GRAVITYDB}"
|
||||||
|
|
||||||
|
colfile="/opt/pihole/COL_TABLE"
|
||||||
|
source "${colfile}"
|
||||||
|
|
||||||
|
# Scan an array of files for matching strings
|
||||||
|
scanList(){
|
||||||
|
# Escape full stops
|
||||||
|
local domain="${1}" esc_domain="${1//./\\.}" lists="${2}" type="${3:-}"
|
||||||
|
|
||||||
|
# Prevent grep from printing file path
|
||||||
|
cd "$piholeDir" || exit 1
|
||||||
|
|
||||||
|
# Prevent grep -i matching slowly: https://bit.ly/2xFXtUX
|
||||||
|
export LC_CTYPE=C
|
||||||
|
|
||||||
|
# /dev/null forces filename to be printed when only one list has been generated
|
||||||
|
case "${type}" in
|
||||||
|
"exact" ) grep -i -E -l "(^|(?<!#)\\s)${esc_domain}($|\\s|#)" ${lists} /dev/null 2>/dev/null;;
|
||||||
|
# Iterate through each regexp and check whether it matches the domainQuery
|
||||||
|
# If it does, print the matching regexp and continue looping
|
||||||
|
# Input 1 - regexps | Input 2 - domainQuery
|
||||||
|
"regex" )
|
||||||
|
for list in ${lists}; do
|
||||||
|
if [[ "${domain}" =~ ${list} ]]; then
|
||||||
|
printf "%b\n" "${list}";
|
||||||
|
fi
|
||||||
|
done;;
|
||||||
|
* ) grep -i "${esc_domain}" ${lists} /dev/null 2>/dev/null;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "${options}" == "-h" ]] || [[ "${options}" == "--help" ]]; then
|
||||||
|
echo "Usage: pihole -q [option] <domain>
|
||||||
|
Example: 'pihole -q -exact domain.com'
|
||||||
|
Query the adlists for a specified domain
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-exact Search the block lists for exact domain matches
|
||||||
|
-all Return all query matches within a block list
|
||||||
|
-h, --help Show this help dialog"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Handle valid options
|
||||||
|
if [[ "${options}" == *"-bp"* ]]; then
|
||||||
|
exact="exact"; blockpage=true
|
||||||
|
else
|
||||||
|
[[ "${options}" == *"-all"* ]] && all=true
|
||||||
|
if [[ "${options}" == *"-exact"* ]]; then
|
||||||
|
exact="exact"; matchType="exact ${matchType}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Strip valid options, leaving only the domain and invalid options
|
||||||
|
# This allows users to place the options before or after the domain
|
||||||
|
options=$(sed -E 's/ ?-(bp|adlists?|all|exact) ?//g' <<< "${options}")
|
||||||
|
|
||||||
|
# Handle remaining options
|
||||||
|
# If $options contain non ASCII characters, convert to punycode
|
||||||
|
case "${options}" in
|
||||||
|
"" ) str="No domain specified";;
|
||||||
|
*" "* ) str="Unknown query option specified";;
|
||||||
|
*[![:ascii:]]* ) domainQuery=$(idn2 "${options}");;
|
||||||
|
* ) domainQuery="${options}";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ -n "${str:-}" ]]; then
|
||||||
|
echo -e "${str}${COL_NC}\\nTry 'pihole -q --help' for more information."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
scanDatabaseTable() {
|
||||||
|
local domain table type querystr result extra
|
||||||
|
domain="$(printf "%q" "${1}")"
|
||||||
|
table="${2}"
|
||||||
|
type="${3:-}"
|
||||||
|
|
||||||
|
# As underscores are legitimate parts of domains, we escape them when using the LIKE operator.
|
||||||
|
# Underscores are SQLite wildcards matching exactly one character. We obviously want to suppress this
|
||||||
|
# behavior. The "ESCAPE '\'" clause specifies that an underscore preceded by an '\' should be matched
|
||||||
|
# as a literal underscore character. We pretreat the $domain variable accordingly to escape underscores.
|
||||||
|
if [[ "${table}" == "gravity" ]]; then
|
||||||
|
case "${exact}" in
|
||||||
|
"exact" ) querystr="SELECT gravity.domain,adlist.address,adlist.enabled FROM gravity LEFT JOIN adlist ON adlist.id = gravity.adlist_id WHERE domain = '${domain}'";;
|
||||||
|
* ) querystr="SELECT gravity.domain,adlist.address,adlist.enabled FROM gravity LEFT JOIN adlist ON adlist.id = gravity.adlist_id WHERE domain LIKE '%${domain//_/\\_}%' ESCAPE '\\'";;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
case "${exact}" in
|
||||||
|
"exact" ) querystr="SELECT domain,enabled FROM domainlist WHERE type = '${type}' AND domain = '${domain}'";;
|
||||||
|
* ) querystr="SELECT domain,enabled FROM domainlist WHERE type = '${type}' AND domain LIKE '%${domain//_/\\_}%' ESCAPE '\\'";;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Send prepared query to gravity database
|
||||||
|
result="$(sqlite3 "${gravityDBfile}" "${querystr}")" 2> /dev/null
|
||||||
|
if [[ -z "${result}" ]]; then
|
||||||
|
# Return early when there are no matches in this table
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${table}" == "gravity" ]]; then
|
||||||
|
echo "${result}"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Mark domain as having been white-/blacklist matched (global variable)
|
||||||
|
wbMatch=true
|
||||||
|
|
||||||
|
# Print table name
|
||||||
|
if [[ -z "${blockpage}" ]]; then
|
||||||
|
echo " ${matchType^} found in ${COL_BOLD}exact ${table}${COL_NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Loop over results and print them
|
||||||
|
mapfile -t results <<< "${result}"
|
||||||
|
for result in "${results[@]}"; do
|
||||||
|
if [[ -n "${blockpage}" ]]; then
|
||||||
|
echo "π ${result}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
domain="${result/|*}"
|
||||||
|
if [[ "${result#*|}" == "0" ]]; then
|
||||||
|
extra=" (disabled)"
|
||||||
|
else
|
||||||
|
extra=""
|
||||||
|
fi
|
||||||
|
echo " ${domain}${extra}"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
scanRegexDatabaseTable() {
|
||||||
|
local domain list
|
||||||
|
domain="${1}"
|
||||||
|
list="${2}"
|
||||||
|
type="${3:-}"
|
||||||
|
|
||||||
|
# Query all regex from the corresponding database tables
|
||||||
|
mapfile -t regexList < <(sqlite3 "${gravityDBfile}" "SELECT domain FROM domainlist WHERE type = ${type}" 2> /dev/null)
|
||||||
|
|
||||||
|
# If we have regexps to process
|
||||||
|
if [[ "${#regexList[@]}" -ne 0 ]]; then
|
||||||
|
# Split regexps over a new line
|
||||||
|
str_regexList=$(printf '%s\n' "${regexList[@]}")
|
||||||
|
# Check domain against regexps
|
||||||
|
mapfile -t regexMatches < <(scanList "${domain}" "${str_regexList}" "regex")
|
||||||
|
# If there were regex matches
|
||||||
|
if [[ "${#regexMatches[@]}" -ne 0 ]]; then
|
||||||
|
# Split matching regexps over a new line
|
||||||
|
str_regexMatches=$(printf '%s\n' "${regexMatches[@]}")
|
||||||
|
# Form a "matched" message
|
||||||
|
str_message="${matchType^} found in ${COL_BOLD}regex ${list}${COL_NC}"
|
||||||
|
# Form a "results" message
|
||||||
|
str_result="${COL_BOLD}${str_regexMatches}${COL_NC}"
|
||||||
|
# If we are displaying more than just the source of the block
|
||||||
|
if [[ -z "${blockpage}" ]]; then
|
||||||
|
# Set the wildcard match flag
|
||||||
|
wcMatch=true
|
||||||
|
# Echo the "matched" message, indented by one space
|
||||||
|
echo " ${str_message}"
|
||||||
|
# Echo the "results" message, each line indented by three spaces
|
||||||
|
# shellcheck disable=SC2001
|
||||||
|
echo "${str_result}" | sed 's/^/ /'
|
||||||
|
else
|
||||||
|
echo "π .wildcard"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Scan Whitelist and Blacklist
|
||||||
|
scanDatabaseTable "${domainQuery}" "whitelist" "0"
|
||||||
|
scanDatabaseTable "${domainQuery}" "blacklist" "1"
|
||||||
|
|
||||||
|
# Scan Regex table
|
||||||
|
scanRegexDatabaseTable "${domainQuery}" "whitelist" "2"
|
||||||
|
scanRegexDatabaseTable "${domainQuery}" "blacklist" "3"
|
||||||
|
|
||||||
|
# Query block lists
|
||||||
|
mapfile -t results <<< "$(scanDatabaseTable "${domainQuery}" "gravity")"
|
||||||
|
|
||||||
|
# Handle notices
|
||||||
|
if [[ -z "${wbMatch:-}" ]] && [[ -z "${wcMatch:-}" ]] && [[ -z "${results[*]}" ]]; then
|
||||||
|
echo -e " ${INFO} No ${exact/t/t }results found for ${COL_BOLD}${domainQuery}${COL_NC} within the block lists"
|
||||||
|
exit 0
|
||||||
|
elif [[ -z "${results[*]}" ]]; then
|
||||||
|
# Result found in WL/BL/Wildcards
|
||||||
|
exit 0
|
||||||
|
elif [[ -z "${all}" ]] && [[ "${#results[*]}" -ge 100 ]]; then
|
||||||
|
echo -e " ${INFO} Over 100 ${exact/t/t }results found for ${COL_BOLD}${domainQuery}${COL_NC}
|
||||||
|
This can be overridden using the -all option"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Print "Exact matches for" title
|
||||||
|
if [[ -n "${exact}" ]] && [[ -z "${blockpage}" ]]; then
|
||||||
|
plural=""; [[ "${#results[*]}" -gt 1 ]] && plural="es"
|
||||||
|
echo " ${matchType^}${plural} for ${COL_BOLD}${domainQuery}${COL_NC} found in:"
|
||||||
|
fi
|
||||||
|
|
||||||
|
for result in "${results[@]}"; do
|
||||||
|
match="${result/|*/}"
|
||||||
|
extra="${result#*|}"
|
||||||
|
adlistAddress="${extra/|*/}"
|
||||||
|
extra="${extra#*|}"
|
||||||
|
if [[ "${extra}" == "0" ]]; then
|
||||||
|
extra="(disabled)"
|
||||||
|
else
|
||||||
|
extra=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "${blockpage}" ]]; then
|
||||||
|
echo "0 ${adlistAddress}"
|
||||||
|
elif [[ -n "${exact}" ]]; then
|
||||||
|
echo " - ${adlistAddress} ${extra}"
|
||||||
|
else
|
||||||
|
if [[ ! "${adlistAddress}" == "${adlistAddress_prev:-}" ]]; then
|
||||||
|
count=""
|
||||||
|
echo " ${matchType^} found in ${COL_BOLD}${adlistAddress}${COL_NC}:"
|
||||||
|
adlistAddress_prev="${adlistAddress}"
|
||||||
|
fi
|
||||||
|
: $((count++))
|
||||||
|
|
||||||
|
# Print matching domain if $max_count has not been reached
|
||||||
|
[[ -z "${all}" ]] && max_count="50"
|
||||||
|
if [[ -z "${all}" ]] && [[ "${count}" -ge "${max_count}" ]]; then
|
||||||
|
[[ "${count}" -gt "${max_count}" ]] && continue
|
||||||
|
echo " ${COL_GRAY}Over ${count} results found, skipping rest of file${COL_NC}"
|
||||||
|
else
|
||||||
|
echo " ${match} ${extra}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 0
|
||||||
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 "Unrecognized init system"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Borrowed from adafruit-pitft-helper:
|
||||||
|
# https://github.com/adafruit/Adafruit-PiTFT-Helper/blob/master/adafruit-pitft-helper#L274-L285
|
||||||
|
autoLoginPiToConsole() {
|
||||||
|
if [ -e /etc/init.d/lightdm ]; then
|
||||||
|
if [ ${SYSTEMD} -eq 1 ]; then
|
||||||
|
systemctl set-default multi-user.target
|
||||||
|
ln -fs /etc/systemd/system/autologin@.service /etc/systemd/system/getty.target.wants/getty@tty1.service
|
||||||
|
else
|
||||||
|
update-rc.d lightdm disable 2
|
||||||
|
sed /etc/inittab -i -e "s/1:2345:respawn:\/sbin\/getty --noclear 38400 tty1/1:2345:respawn:\/bin\/login -f pi tty1 <\/dev\/tty1 >\/dev\/tty1 2>&1/"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
######### SCRIPT ###########
|
||||||
|
# Set pi to log in automatically
|
||||||
|
getInitSys
|
||||||
|
autoLoginPiToConsole
|
||||||
|
|
||||||
|
# Set chronomter to run automatically when pi logs in
|
||||||
|
echo /usr/local/bin/chronometer.sh >> /home/pi/.bashrc
|
||||||
|
# OR
|
||||||
|
#$SUDO echo /usr/local/bin/chronometer.sh >> /etc/profile
|
||||||
|
|
||||||
|
# Set up the LCD screen based on Adafruits instuctions:
|
||||||
|
# https://learn.adafruit.com/adafruit-pitft-28-inch-resistive-touchscreen-display-raspberry-pi/easy-install
|
||||||
|
curl -SLs https://apt.adafruit.com/add-pin | bash
|
||||||
|
apt-get -y install raspberrypi-bootloader
|
||||||
|
apt-get -y install adafruit-pitft-helper
|
||||||
|
adafruit-pitft-helper -t 28r
|
||||||
|
|
||||||
|
# Download the cmdline.txt file that prevents the screen from going blank after a period of time
|
||||||
|
mv /boot/cmdline.txt /boot/cmdline.orig
|
||||||
|
curl -o /boot/cmdline.txt https://raw.githubusercontent.com/pi-hole/pi-hole/master/advanced/cmdline.txt
|
||||||
|
|
||||||
|
# Back up the original file and download the new one
|
||||||
|
mv /etc/default/console-setup /etc/default/console-setup.orig
|
||||||
|
curl -o /etc/default/console-setup https://raw.githubusercontent.com/pi-hole/pi-hole/master/advanced/console-setup
|
||||||
|
|
||||||
|
# Instantly apply the font change to the LCD screen
|
||||||
|
setupcon
|
||||||
|
|
||||||
|
reboot
|
||||||
|
|
||||||
|
# Start showing the stats on the screen by running the command on another tty:
|
||||||
|
# https://unix.stackexchange.com/questions/170063/start-a-process-on-a-different-tty
|
||||||
|
#setsid sh -c 'exec /usr/local/bin/chronometer.sh <> /dev/tty1 >&0 2>&1'
|
||||||
233
advanced/Scripts/update.sh
Executable file
233
advanced/Scripts/update.sh
Executable file
@@ -0,0 +1,233 @@
|
|||||||
|
#!/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"
|
||||||
|
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
PH_TEST=true
|
||||||
|
|
||||||
|
# when --check-only is passed to this script, it will not perform the actual update
|
||||||
|
CHECK_ONLY=false
|
||||||
|
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source "/opt/pihole/COL_TABLE"
|
||||||
|
|
||||||
|
# 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
|
||||||
|
# FTLcheckUpdate() sourced from basic-install.sh
|
||||||
|
|
||||||
|
GitCheckUpdateAvail() {
|
||||||
|
local directory
|
||||||
|
local curBranch
|
||||||
|
directory="${1}"
|
||||||
|
curdir=$PWD
|
||||||
|
cd "${directory}" || return
|
||||||
|
|
||||||
|
# Fetch latest changes in this repo
|
||||||
|
git fetch --tags --quiet origin
|
||||||
|
|
||||||
|
# Check current branch. If it is master, then check for the latest available tag instead of latest commit.
|
||||||
|
curBranch=$(git rev-parse --abbrev-ref HEAD)
|
||||||
|
if [[ "${curBranch}" == "master" ]]; then
|
||||||
|
# get the latest local tag
|
||||||
|
LOCAL=$(git describe --abbrev=0 --tags master)
|
||||||
|
# get the latest tag from remote
|
||||||
|
REMOTE=$(git describe --abbrev=0 --tags origin/master)
|
||||||
|
|
||||||
|
else
|
||||||
|
# @ 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}")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if [[ "${#LOCAL}" == 0 ]]; then
|
||||||
|
echo -e "\\n ${COL_LIGHT_RED}Error: Local revision could not be obtained, please contact Pi-hole Support"
|
||||||
|
echo -e " Additional debugging output:${COL_NC}"
|
||||||
|
git status
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
if [[ "${#REMOTE}" == 0 ]]; then
|
||||||
|
echo -e "\\n ${COL_LIGHT_RED}Error: Remote revision could not be obtained, please contact Pi-hole Support"
|
||||||
|
echo -e " Additional debugging output:${COL_NC}"
|
||||||
|
git status
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Change back to original directory
|
||||||
|
cd "${curdir}" || exit
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
local basicError="\\n ${COL_LIGHT_RED}Unable to complete update, please contact Pi-hole Support${COL_NC}"
|
||||||
|
local core_update
|
||||||
|
local web_update
|
||||||
|
local FTL_update
|
||||||
|
|
||||||
|
core_update=false
|
||||||
|
web_update=false
|
||||||
|
FTL_update=false
|
||||||
|
|
||||||
|
# shellcheck disable=1090,2154
|
||||||
|
source "${setupVars}"
|
||||||
|
|
||||||
|
# Install packages used by this installation script (necessary if users have removed e.g. git from their systems)
|
||||||
|
package_manager_detect
|
||||||
|
install_dependent_packages "${INSTALLER_DEPS[@]}"
|
||||||
|
|
||||||
|
# This is unlikely
|
||||||
|
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
|
||||||
|
echo -e "\\n ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!"
|
||||||
|
echo -e " Please re-run install script from https://pi-hole.net${COL_NC}"
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e " ${INFO} Checking for updates..."
|
||||||
|
|
||||||
|
if GitCheckUpdateAvail "${PI_HOLE_FILES_DIR}" ; then
|
||||||
|
core_update=true
|
||||||
|
echo -e " ${INFO} Pi-hole Core:\\t${COL_YELLOW}update available${COL_NC}"
|
||||||
|
else
|
||||||
|
core_update=false
|
||||||
|
echo -e " ${INFO} Pi-hole Core:\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||||
|
if ! is_repo "${ADMIN_INTERFACE_DIR}" ; then
|
||||||
|
echo -e "\\n ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!"
|
||||||
|
echo -e " Please re-run install script from https://pi-hole.net${COL_NC}"
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if GitCheckUpdateAvail "${ADMIN_INTERFACE_DIR}" ; then
|
||||||
|
web_update=true
|
||||||
|
echo -e " ${INFO} Web Interface:\\t${COL_YELLOW}update available${COL_NC}"
|
||||||
|
else
|
||||||
|
web_update=false
|
||||||
|
echo -e " ${INFO} Web Interface:\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
local funcOutput
|
||||||
|
funcOutput=$(get_binary_name) #Store output of get_binary_name here
|
||||||
|
local binary
|
||||||
|
binary="pihole-FTL${funcOutput##*pihole-FTL}" #binary name will be the last line of the output of get_binary_name (it always begins with pihole-FTL)
|
||||||
|
|
||||||
|
if FTLcheckUpdate "${binary}" > /dev/null; then
|
||||||
|
FTL_update=true
|
||||||
|
echo -e " ${INFO} FTL:\\t\\t${COL_YELLOW}update available${COL_NC}"
|
||||||
|
else
|
||||||
|
case $? in
|
||||||
|
1)
|
||||||
|
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_RED}Branch is not available.${COL_NC}\\n\\t\\t\\tUse ${COL_LIGHT_GREEN}pihole checkout ftl [branchname]${COL_NC} to switch to a valid branch."
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_RED}Something has gone wrong, contact support${COL_NC}"
|
||||||
|
esac
|
||||||
|
FTL_update=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine FTL branch
|
||||||
|
local ftlBranch
|
||||||
|
if [[ -f "/etc/pihole/ftlbranch" ]]; then
|
||||||
|
ftlBranch=$(</etc/pihole/ftlbranch)
|
||||||
|
else
|
||||||
|
ftlBranch="master"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! "${ftlBranch}" == "master" && ! "${ftlBranch}" == "development" ]]; then
|
||||||
|
# Notify user that they are on a custom branch which might mean they they are lost
|
||||||
|
# behind if a branch was merged to development and got abandoned
|
||||||
|
printf " %b %bWarning:%b You are using FTL from a custom branch (%s) and might be missing future releases.\\n" "${INFO}" "${COL_LIGHT_RED}" "${COL_NC}" "${ftlBranch}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${core_update}" == false && "${web_update}" == false && "${FTL_update}" == false ]]; then
|
||||||
|
echo ""
|
||||||
|
echo -e " ${TICK} Everything is up to date!"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${CHECK_ONLY}" == true ]]; then
|
||||||
|
echo ""
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${core_update}" == true ]]; then
|
||||||
|
echo ""
|
||||||
|
echo -e " ${INFO} Pi-hole core files out of date, updating local repo."
|
||||||
|
getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}"
|
||||||
|
echo -e " ${INFO} If you had made any changes in '/etc/.pihole/', they have been stashed using 'git stash'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${web_update}" == true ]]; then
|
||||||
|
echo ""
|
||||||
|
echo -e " ${INFO} Pi-hole Web Admin files out of date, updating local repo."
|
||||||
|
getGitFiles "${ADMIN_INTERFACE_DIR}" "${ADMIN_INTERFACE_GIT_URL}"
|
||||||
|
echo -e " ${INFO} If you had made any changes in '/var/www/html/admin/', they have been stashed using 'git stash'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${FTL_update}" == true ]]; then
|
||||||
|
echo ""
|
||||||
|
echo -e " ${INFO} FTL out of date, it will be updated by the installer."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${FTL_update}" == true || "${core_update}" == true ]]; then
|
||||||
|
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || \
|
||||||
|
echo -e "${basicError}" && exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${FTL_update}" == true || "${core_update}" == true || "${web_update}" == true ]]; then
|
||||||
|
# Force an update of the updatechecker
|
||||||
|
/opt/pihole/updatecheck.sh
|
||||||
|
/opt/pihole/updatecheck.sh x remote
|
||||||
|
echo -e " ${INFO} Local version file information updated."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "$1" == "--check-only" ]]; then
|
||||||
|
CHECK_ONLY=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
main
|
||||||
94
advanced/Scripts/updatecheck.sh
Executable file
94
advanced/Scripts/updatecheck.sh
Executable file
@@ -0,0 +1,94 @@
|
|||||||
|
#!/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.
|
||||||
|
#
|
||||||
|
# Checks for local or remote versions and branches
|
||||||
|
#
|
||||||
|
# This file is copyright under the latest version of the EUPL.
|
||||||
|
# Please see LICENSE file for your rights under this license.
|
||||||
|
|
||||||
|
# Credit: https://stackoverflow.com/a/46324904
|
||||||
|
function json_extract() {
|
||||||
|
local key=$1
|
||||||
|
local json=$2
|
||||||
|
|
||||||
|
local string_regex='"([^"\]|\\.)*"'
|
||||||
|
local number_regex='-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?'
|
||||||
|
local value_regex="${string_regex}|${number_regex}|true|false|null"
|
||||||
|
local pair_regex="\"${key}\"[[:space:]]*:[[:space:]]*(${value_regex})"
|
||||||
|
|
||||||
|
if [[ ${json} =~ ${pair_regex} ]]; then
|
||||||
|
echo $(sed 's/^"\|"$//g' <<< "${BASH_REMATCH[1]}")
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_local_branch() {
|
||||||
|
# Return active branch
|
||||||
|
cd "${1}" 2> /dev/null || return 1
|
||||||
|
git rev-parse --abbrev-ref HEAD || return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_local_version() {
|
||||||
|
# Return active branch
|
||||||
|
cd "${1}" 2> /dev/null || return 1
|
||||||
|
git describe --long --dirty --tags 2> /dev/null || return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Source the setupvars config file
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
. /etc/pihole/setupVars.conf
|
||||||
|
|
||||||
|
if [[ "$2" == "remote" ]]; then
|
||||||
|
|
||||||
|
if [[ "$3" == "reboot" ]]; then
|
||||||
|
sleep 30
|
||||||
|
fi
|
||||||
|
|
||||||
|
GITHUB_VERSION_FILE="/etc/pihole/GitHubVersions"
|
||||||
|
|
||||||
|
GITHUB_CORE_VERSION="$(json_extract tag_name "$(curl -s 'https://api.github.com/repos/pi-hole/pi-hole/releases/latest' 2> /dev/null)")"
|
||||||
|
echo -n "${GITHUB_CORE_VERSION}" > "${GITHUB_VERSION_FILE}"
|
||||||
|
chmod 644 "${GITHUB_VERSION_FILE}"
|
||||||
|
|
||||||
|
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||||
|
GITHUB_WEB_VERSION="$(json_extract tag_name "$(curl -s 'https://api.github.com/repos/pi-hole/AdminLTE/releases/latest' 2> /dev/null)")"
|
||||||
|
echo -n " ${GITHUB_WEB_VERSION}" >> "${GITHUB_VERSION_FILE}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
GITHUB_FTL_VERSION="$(json_extract tag_name "$(curl -s 'https://api.github.com/repos/pi-hole/FTL/releases/latest' 2> /dev/null)")"
|
||||||
|
echo -n " ${GITHUB_FTL_VERSION}" >> "${GITHUB_VERSION_FILE}"
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
LOCAL_BRANCH_FILE="/etc/pihole/localbranches"
|
||||||
|
|
||||||
|
CORE_BRANCH="$(get_local_branch /etc/.pihole)"
|
||||||
|
echo -n "${CORE_BRANCH}" > "${LOCAL_BRANCH_FILE}"
|
||||||
|
chmod 644 "${LOCAL_BRANCH_FILE}"
|
||||||
|
|
||||||
|
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||||
|
WEB_BRANCH="$(get_local_branch /var/www/html/admin)"
|
||||||
|
echo -n " ${WEB_BRANCH}" >> "${LOCAL_BRANCH_FILE}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
FTL_BRANCH="$(pihole-FTL branch)"
|
||||||
|
echo -n " ${FTL_BRANCH}" >> "${LOCAL_BRANCH_FILE}"
|
||||||
|
|
||||||
|
LOCAL_VERSION_FILE="/etc/pihole/localversions"
|
||||||
|
|
||||||
|
CORE_VERSION="$(get_local_version /etc/.pihole)"
|
||||||
|
echo -n "${CORE_VERSION}" > "${LOCAL_VERSION_FILE}"
|
||||||
|
chmod 644 "${LOCAL_VERSION_FILE}"
|
||||||
|
|
||||||
|
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||||
|
WEB_VERSION="$(get_local_version /var/www/html/admin)"
|
||||||
|
echo -n " ${WEB_VERSION}" >> "${LOCAL_VERSION_FILE}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
FTL_VERSION="$(pihole-FTL version)"
|
||||||
|
echo -n " ${FTL_VERSION}" >> "${LOCAL_VERSION_FILE}"
|
||||||
|
|
||||||
|
fi
|
||||||
224
advanced/Scripts/version.sh
Executable file
224
advanced/Scripts/version.sh
Executable file
@@ -0,0 +1,224 @@
|
|||||||
|
#!/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/"
|
||||||
|
|
||||||
|
# Source the setupvars config file
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source /etc/pihole/setupVars.conf
|
||||||
|
|
||||||
|
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
|
||||||
|
local cachedVersions
|
||||||
|
local arrCache
|
||||||
|
cachedVersions="/etc/pihole/GitHubVersions"
|
||||||
|
|
||||||
|
#If the above file exists, then we can read from that. Prevents overuse of GitHub API
|
||||||
|
if [[ -f "$cachedVersions" ]]; then
|
||||||
|
IFS=' ' read -r -a arrCache < "$cachedVersions"
|
||||||
|
|
||||||
|
case $daemon in
|
||||||
|
"pi-hole" ) echo "${arrCache[0]}";;
|
||||||
|
"AdminLTE" ) [[ "${INSTALL_WEB_INTERFACE}" == true ]] && echo "${arrCache[1]}";;
|
||||||
|
"FTL" ) [[ "${INSTALL_WEB_INTERFACE}" == true ]] && echo "${arrCache[2]}" || echo "${arrCache[1]}";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
version=$(curl --silent --fail "https://api.github.com/repos/pi-hole/${daemon}/releases/latest" | \
|
||||||
|
awk -F: '$1 ~/tag_name/ { print $2 }' | \
|
||||||
|
tr -cd '[[:alnum:]]._-')
|
||||||
|
if [[ "${version}" =~ ^v ]]; then
|
||||||
|
echo "${version}"
|
||||||
|
else
|
||||||
|
echo "ERROR"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
getLocalBranch(){
|
||||||
|
# Get the checked out branch of the local directory
|
||||||
|
local directory="${1}"
|
||||||
|
local branch
|
||||||
|
|
||||||
|
# Local FTL btranch is stored in /etc/pihole/ftlbranch
|
||||||
|
if [[ "$1" == "FTL" ]]; then
|
||||||
|
branch="$(pihole-FTL branch)"
|
||||||
|
else
|
||||||
|
cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; }
|
||||||
|
branch=$(git rev-parse --abbrev-ref HEAD || echo "$DEFAULT")
|
||||||
|
fi
|
||||||
|
if [[ ! "${branch}" =~ ^v ]]; then
|
||||||
|
if [[ "${branch}" == "master" ]]; then
|
||||||
|
echo ""
|
||||||
|
elif [[ "${branch}" == "HEAD" ]]; then
|
||||||
|
echo "in detached HEAD state at "
|
||||||
|
else
|
||||||
|
echo "${branch} "
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Branch started in "v"
|
||||||
|
echo "release "
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
versionOutput() {
|
||||||
|
if [[ "$1" == "AdminLTE" && "${INSTALL_WEB_INTERFACE}" != true ]]; then
|
||||||
|
echo " WebAdmin not installed"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ "$1" == "pi-hole" ]] && GITDIR=$COREGITDIR
|
||||||
|
[[ "$1" == "AdminLTE" ]] && GITDIR=$WEBGITDIR
|
||||||
|
[[ "$1" == "FTL" ]] && GITDIR="FTL"
|
||||||
|
|
||||||
|
[[ "$2" == "-c" ]] || [[ "$2" == "--current" ]] || [[ -z "$2" ]] && current=$(getLocalVersion $GITDIR) && branch=$(getLocalBranch $GITDIR)
|
||||||
|
[[ "$2" == "-l" ]] || [[ "$2" == "--latest" ]] || [[ -z "$2" ]] && latest=$(getRemoteVersion "$1")
|
||||||
|
if [[ "$2" == "-h" ]] || [[ "$2" == "--hash" ]]; then
|
||||||
|
[[ "$3" == "-c" ]] || [[ "$3" == "--current" ]] || [[ -z "$3" ]] && curHash=$(getLocalHash "$GITDIR") && branch=$(getLocalBranch $GITDIR)
|
||||||
|
[[ "$3" == "-l" ]] || [[ "$3" == "--latest" ]] || [[ -z "$3" ]] && latHash=$(getRemoteHash "$1" "$(cd "$GITDIR" 2> /dev/null && git rev-parse --abbrev-ref HEAD)")
|
||||||
|
fi
|
||||||
|
if [[ -n "$current" ]] && [[ -n "$latest" ]]; then
|
||||||
|
output="${1^} version is $branch$current (Latest: $latest)"
|
||||||
|
elif [[ -n "$current" ]] && [[ -z "$latest" ]]; then
|
||||||
|
output="Current ${1^} version is $branch$current"
|
||||||
|
elif [[ -z "$current" ]] && [[ -n "$latest" ]]; then
|
||||||
|
output="Latest ${1^} version is $latest"
|
||||||
|
elif [[ "$curHash" == "N/A" ]] || [[ "$latHash" == "N/A" ]]; then
|
||||||
|
output="${1^} hash is not applicable"
|
||||||
|
elif [[ -n "$curHash" ]] && [[ -n "$latHash" ]]; then
|
||||||
|
output="${1^} hash is $curHash (Latest: $latHash)"
|
||||||
|
elif [[ -n "$curHash" ]] && [[ -z "$latHash" ]]; then
|
||||||
|
output="Current ${1^} hash is $curHash"
|
||||||
|
elif [[ -z "$curHash" ]] && [[ -n "$latHash" ]]; then
|
||||||
|
output="Latest ${1^} hash is $latHash"
|
||||||
|
else
|
||||||
|
errorOutput
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ -n "$output" ]] && echo " $output"
|
||||||
|
}
|
||||||
|
|
||||||
|
errorOutput() {
|
||||||
|
echo " Invalid Option! Try 'pihole -v --help' for more information."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultOutput() {
|
||||||
|
versionOutput "pi-hole" "$@"
|
||||||
|
|
||||||
|
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||||
|
versionOutput "AdminLTE" "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
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
|
||||||
846
advanced/Scripts/webpage.sh
Executable file
846
advanced/Scripts/webpage.sh
Executable file
@@ -0,0 +1,846 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
|
||||||
|
# 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 dnsmasqconfig="/etc/dnsmasq.d/01-pihole.conf"
|
||||||
|
readonly dhcpconfig="/etc/dnsmasq.d/02-pihole-dhcp.conf"
|
||||||
|
readonly FTLconf="/etc/pihole/pihole-FTL.conf"
|
||||||
|
# 03 -> wildcards
|
||||||
|
readonly dhcpstaticconfig="/etc/dnsmasq.d/04-pihole-static-dhcp.conf"
|
||||||
|
readonly dnscustomfile="/etc/pihole/custom.list"
|
||||||
|
readonly dnscustomcnamefile="/etc/dnsmasq.d/05-pihole-custom-cname.conf"
|
||||||
|
|
||||||
|
readonly gravityDBfile="/etc/pihole/gravity.db"
|
||||||
|
|
||||||
|
# Source install script for ${setupVars}, ${PI_HOLE_BIN_DIR} and valid_ip()
|
||||||
|
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
|
||||||
|
# shellcheck disable=SC2034 # used in basic-install
|
||||||
|
PH_TEST="true"
|
||||||
|
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
|
||||||
|
|
||||||
|
coltable="/opt/pihole/COL_TABLE"
|
||||||
|
if [[ -f ${coltable} ]]; then
|
||||||
|
source ${coltable}
|
||||||
|
fi
|
||||||
|
|
||||||
|
helpFunc() {
|
||||||
|
echo "Usage: pihole -a [options]
|
||||||
|
Example: pihole -a -p password
|
||||||
|
Set options for the Admin Console
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-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
|
||||||
|
-e, email Set an administrative contact address for the Block Page
|
||||||
|
-h, --help Show this help dialog
|
||||||
|
-i, interface Specify dnsmasq's interface listening behavior
|
||||||
|
-l, privacylevel Set privacy level (0 = lowest, 3 = highest)
|
||||||
|
-t, teleporter Backup configuration as an archive"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
add_setting() {
|
||||||
|
echo "${1}=${2}" >> "${setupVars}"
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_setting() {
|
||||||
|
sed -i "/^${1}/d" "${setupVars}"
|
||||||
|
}
|
||||||
|
|
||||||
|
change_setting() {
|
||||||
|
delete_setting "${1}"
|
||||||
|
add_setting "${1}" "${2}"
|
||||||
|
}
|
||||||
|
|
||||||
|
addFTLsetting() {
|
||||||
|
echo "${1}=${2}" >> "${FTLconf}"
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteFTLsetting() {
|
||||||
|
sed -i "/^${1}/d" "${FTLconf}"
|
||||||
|
}
|
||||||
|
|
||||||
|
changeFTLsetting() {
|
||||||
|
deleteFTLsetting "${1}"
|
||||||
|
addFTLsetting "${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}"
|
||||||
|
echo -e " ${TICK} Set temperature unit to ${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
|
||||||
|
# Prevents a bug if the user presses Ctrl+C and it continues to hide the text typed.
|
||||||
|
# So we reset the terminal via stty if the user does press Ctrl+C
|
||||||
|
trap '{ echo -e "\nNo password will be set" ; stty sane ; exit 1; }' INT
|
||||||
|
read -s -r -p "Enter New Password (Blank for no password): " PASSWORD
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [ "${PASSWORD}" == "" ]; then
|
||||||
|
change_setting "WEBPASSWORD" ""
|
||||||
|
echo -e " ${TICK} Password Removed"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
read -s -r -p "Confirm Password: " CONFIRM
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${PASSWORD}" == "${CONFIRM}" ] ; then
|
||||||
|
# We do not wrap this in brackets, otherwise BASH will expand any appropriate syntax
|
||||||
|
hash=$(HashPassword "$PASSWORD")
|
||||||
|
# Save hash to file
|
||||||
|
change_setting "WEBPASSWORD" "${hash}"
|
||||||
|
echo -e " ${TICK} New password set"
|
||||||
|
else
|
||||||
|
echo -e " ${CROSS} Passwords don't match. Your password has not been changed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessDNSSettings() {
|
||||||
|
source "${setupVars}"
|
||||||
|
|
||||||
|
delete_dnsmasq_setting "server"
|
||||||
|
|
||||||
|
COUNTER=1
|
||||||
|
while true ; do
|
||||||
|
var=PIHOLE_DNS_${COUNTER}
|
||||||
|
if [ -z "${!var}" ]; then
|
||||||
|
break;
|
||||||
|
fi
|
||||||
|
add_dnsmasq_setting "server" "${!var}"
|
||||||
|
(( COUNTER++ ))
|
||||||
|
done
|
||||||
|
|
||||||
|
# The option LOCAL_DNS_PORT is deprecated
|
||||||
|
# We apply it once more, and then convert it into the current format
|
||||||
|
if [ -n "${LOCAL_DNS_PORT}" ]; then
|
||||||
|
add_dnsmasq_setting "server" "127.0.0.1#${LOCAL_DNS_PORT}"
|
||||||
|
add_setting "PIHOLE_DNS_${COUNTER}" "127.0.0.1#${LOCAL_DNS_PORT}"
|
||||||
|
delete_setting "LOCAL_DNS_PORT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
delete_dnsmasq_setting "domain-needed"
|
||||||
|
delete_dnsmasq_setting "expand-hosts"
|
||||||
|
|
||||||
|
if [[ "${DNS_FQDN_REQUIRED}" == true ]]; then
|
||||||
|
add_dnsmasq_setting "domain-needed"
|
||||||
|
add_dnsmasq_setting "expand-hosts"
|
||||||
|
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=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D
|
||||||
|
" >> "${dnsmasqconfig}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
delete_dnsmasq_setting "host-record"
|
||||||
|
|
||||||
|
if [ -n "${HOSTRECORD}" ]; then
|
||||||
|
add_dnsmasq_setting "host-record" "${HOSTRECORD}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Setup interface listening behavior of dnsmasq
|
||||||
|
delete_dnsmasq_setting "interface"
|
||||||
|
delete_dnsmasq_setting "local-service"
|
||||||
|
delete_dnsmasq_setting "except-interface"
|
||||||
|
delete_dnsmasq_setting "bind-interfaces"
|
||||||
|
|
||||||
|
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
|
||||||
|
# Options "bind" and "single"
|
||||||
|
# Listen only on one interface
|
||||||
|
# Use eth0 as fallback interface if interface is missing in setupVars.conf
|
||||||
|
if [ -z "${PIHOLE_INTERFACE}" ]; then
|
||||||
|
PIHOLE_INTERFACE="eth0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
add_dnsmasq_setting "interface" "${PIHOLE_INTERFACE}"
|
||||||
|
|
||||||
|
if [[ "${DNSMASQ_LISTENING}" == "bind" ]]; then
|
||||||
|
# Really bind to interface
|
||||||
|
add_dnsmasq_setting "bind-interfaces"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${CONDITIONAL_FORWARDING}" == true ]]; then
|
||||||
|
# Convert legacy "conditional forwarding" to rev-server configuration
|
||||||
|
# Remove any existing REV_SERVER settings
|
||||||
|
delete_setting "REV_SERVER"
|
||||||
|
delete_setting "REV_SERVER_DOMAIN"
|
||||||
|
delete_setting "REV_SERVER_TARGET"
|
||||||
|
delete_setting "REV_SERVER_CIDR"
|
||||||
|
|
||||||
|
REV_SERVER=true
|
||||||
|
add_setting "REV_SERVER" "true"
|
||||||
|
|
||||||
|
REV_SERVER_DOMAIN="${CONDITIONAL_FORWARDING_DOMAIN}"
|
||||||
|
add_setting "REV_SERVER_DOMAIN" "${REV_SERVER_DOMAIN}"
|
||||||
|
|
||||||
|
REV_SERVER_TARGET="${CONDITIONAL_FORWARDING_IP}"
|
||||||
|
add_setting "REV_SERVER_TARGET" "${REV_SERVER_TARGET}"
|
||||||
|
|
||||||
|
#Convert CONDITIONAL_FORWARDING_REVERSE if necessary e.g:
|
||||||
|
# 1.1.168.192.in-addr.arpa to 192.168.1.1/32
|
||||||
|
# 1.168.192.in-addr.arpa to 192.168.1.0/24
|
||||||
|
# 168.192.in-addr.arpa to 192.168.0.0/16
|
||||||
|
# 192.in-addr.arpa to 192.0.0.0/8
|
||||||
|
if [[ "${CONDITIONAL_FORWARDING_REVERSE}" == *"in-addr.arpa" ]];then
|
||||||
|
arrRev=("${CONDITIONAL_FORWARDING_REVERSE//./ }")
|
||||||
|
case ${#arrRev[@]} in
|
||||||
|
6 ) REV_SERVER_CIDR="${arrRev[3]}.${arrRev[2]}.${arrRev[1]}.${arrRev[0]}/32";;
|
||||||
|
5 ) REV_SERVER_CIDR="${arrRev[2]}.${arrRev[1]}.${arrRev[0]}.0/24";;
|
||||||
|
4 ) REV_SERVER_CIDR="${arrRev[1]}.${arrRev[0]}.0.0/16";;
|
||||||
|
3 ) REV_SERVER_CIDR="${arrRev[0]}.0.0.0/8";;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
# Set REV_SERVER_CIDR to whatever value it was set to
|
||||||
|
REV_SERVER_CIDR="${CONDITIONAL_FORWARDING_REVERSE}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If REV_SERVER_CIDR is not converted by the above, then use the REV_SERVER_TARGET variable to derive it
|
||||||
|
if [ -z "${REV_SERVER_CIDR}" ]; then
|
||||||
|
# Convert existing input to /24 subnet (preserves legacy behavior)
|
||||||
|
# This sed converts "192.168.1.2" to "192.168.1.0/24"
|
||||||
|
# shellcheck disable=2001
|
||||||
|
REV_SERVER_CIDR="$(sed "s+\\.[0-9]*$+\\.0/24+" <<< "${REV_SERVER_TARGET}")"
|
||||||
|
fi
|
||||||
|
add_setting "REV_SERVER_CIDR" "${REV_SERVER_CIDR}"
|
||||||
|
|
||||||
|
# Remove obsolete settings from setupVars.conf
|
||||||
|
delete_setting "CONDITIONAL_FORWARDING"
|
||||||
|
delete_setting "CONDITIONAL_FORWARDING_REVERSE"
|
||||||
|
delete_setting "CONDITIONAL_FORWARDING_DOMAIN"
|
||||||
|
delete_setting "CONDITIONAL_FORWARDING_IP"
|
||||||
|
fi
|
||||||
|
|
||||||
|
delete_dnsmasq_setting "rev-server"
|
||||||
|
|
||||||
|
if [[ "${REV_SERVER}" == true ]]; then
|
||||||
|
add_dnsmasq_setting "rev-server=${REV_SERVER_CIDR},${REV_SERVER_TARGET}"
|
||||||
|
if [ -n "${REV_SERVER_DOMAIN}" ]; then
|
||||||
|
# Forward local domain names to the CF target, too
|
||||||
|
add_dnsmasq_setting "server=/${REV_SERVER_DOMAIN}/${REV_SERVER_TARGET}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${DNS_FQDN_REQUIRED}" != true ]]; then
|
||||||
|
# Forward unqualified names to the CF target only when the "never
|
||||||
|
# forward non-FQDN" option is unticked
|
||||||
|
add_dnsmasq_setting "server=//${REV_SERVER_TARGET}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
# We need to process DHCP settings here as well to account for possible
|
||||||
|
# changes in the non-FQDN forwarding. This cannot be done in 01-pihole.conf
|
||||||
|
# as we don't want to delete all local=/.../ lines so it's much safer to
|
||||||
|
# simply rewrite the entire corresponding config file (which is what the
|
||||||
|
# DHCP settings subroutie is doing)
|
||||||
|
ProcessDHCPSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
SetDNSServers() {
|
||||||
|
# Save setting to file
|
||||||
|
delete_setting "PIHOLE_DNS"
|
||||||
|
IFS=',' read -r -a array <<< "${args[2]}"
|
||||||
|
for index in "${!array[@]}"
|
||||||
|
do
|
||||||
|
# Replace possible "\#" by "#". This fixes AdminLTE#1427
|
||||||
|
local ip
|
||||||
|
ip="${array[index]//\\#/#}"
|
||||||
|
|
||||||
|
if valid_ip "${ip}" || valid_ip6 "${ip}" ; then
|
||||||
|
add_setting "PIHOLE_DNS_$((index+1))" "${ip}"
|
||||||
|
else
|
||||||
|
echo -e " ${CROSS} Invalid IP has been passed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
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
|
||||||
|
|
||||||
|
if [[ "${args[6]}" == "rev-server" ]]; then
|
||||||
|
change_setting "REV_SERVER" "true"
|
||||||
|
change_setting "REV_SERVER_CIDR" "${args[7]}"
|
||||||
|
change_setting "REV_SERVER_TARGET" "${args[8]}"
|
||||||
|
change_setting "REV_SERVER_DOMAIN" "${args[9]}"
|
||||||
|
else
|
||||||
|
change_setting "REV_SERVER" "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]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
Poweroff(){
|
||||||
|
nohup bash -c "sleep 5; poweroff" &> /dev/null </dev/null &
|
||||||
|
}
|
||||||
|
|
||||||
|
Reboot() {
|
||||||
|
nohup bash -c "sleep 5; reboot" &> /dev/null </dev/null &
|
||||||
|
}
|
||||||
|
|
||||||
|
RestartDNS() {
|
||||||
|
"${PI_HOLE_BIN_DIR}"/pihole restartdns
|
||||||
|
}
|
||||||
|
|
||||||
|
SetQueryLogOptions() {
|
||||||
|
change_setting "API_QUERY_LOG_SHOW" "${args[2]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessDHCPSettings() {
|
||||||
|
source "${setupVars}"
|
||||||
|
|
||||||
|
if [[ "${DHCP_ACTIVE}" == "true" ]]; then
|
||||||
|
interface="${PIHOLE_INTERFACE}"
|
||||||
|
|
||||||
|
# Use eth0 as fallback interface
|
||||||
|
if [ -z ${interface} ]; then
|
||||||
|
interface="eth0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${PIHOLE_DOMAIN}" == "" ]]; then
|
||||||
|
PIHOLE_DOMAIN="lan"
|
||||||
|
change_setting "PIHOLE_DOMAIN" "${PIHOLE_DOMAIN}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${DHCP_LEASETIME}" == "0" ]]; then
|
||||||
|
leasetime="infinite"
|
||||||
|
elif [[ "${DHCP_LEASETIME}" == "" ]]; then
|
||||||
|
leasetime="24"
|
||||||
|
change_setting "DHCP_LEASETIME" "${leasetime}"
|
||||||
|
elif [[ "${DHCP_LEASETIME}" == "24h" ]]; then
|
||||||
|
#Installation is affected by known bug, introduced in a previous version.
|
||||||
|
#This will automatically clean up setupVars.conf and remove the unnecessary "h"
|
||||||
|
leasetime="24"
|
||||||
|
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}"
|
||||||
|
chmod 644 "${dhcpconfig}"
|
||||||
|
|
||||||
|
if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then
|
||||||
|
echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}"
|
||||||
|
|
||||||
|
# When there is a Pi-hole domain set and "Never forward non-FQDNs" is
|
||||||
|
# ticked, we add `local=/domain/` to tell FTL that this domain is purely
|
||||||
|
# local and FTL may answer queries from /etc/hosts or DHCP but should
|
||||||
|
# never forward queries on that domain to any upstream servers
|
||||||
|
if [[ "${DNS_FQDN_REQUIRED}" == true ]]; then
|
||||||
|
echo "local=/${PIHOLE_DOMAIN}/" >> "${dhcpconfig}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Sourced from setupVars
|
||||||
|
# shellcheck disable=SC2154
|
||||||
|
if [[ "${DHCP_rapid_commit}" == "true" ]]; then
|
||||||
|
echo "dhcp-rapid-commit" >> "${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,64,3600
|
||||||
|
ra-param=*,0,0
|
||||||
|
" >> "${dhcpconfig}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
else
|
||||||
|
if [[ -f "${dhcpconfig}" ]]; then
|
||||||
|
rm "${dhcpconfig}" &> /dev/null
|
||||||
|
fi
|
||||||
|
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]}"
|
||||||
|
change_setting "DHCP_rapid_commit" "${args[8]}"
|
||||||
|
|
||||||
|
# Remove possible old setting from file
|
||||||
|
delete_dnsmasq_setting "dhcp-"
|
||||||
|
delete_dnsmasq_setting "quiet-dhcp"
|
||||||
|
|
||||||
|
# If a DHCP client claims that its name is "wpad", ignore that.
|
||||||
|
# This fixes a security hole. see CERT Vulnerability VU#598349
|
||||||
|
# We also ignore "localhost" as Windows behaves strangely if a
|
||||||
|
# device claims this host name
|
||||||
|
add_dnsmasq_setting "dhcp-name-match=set:hostname-ignore,wpad
|
||||||
|
dhcp-name-match=set:hostname-ignore,localhost
|
||||||
|
dhcp-ignore-names=tag:hostname-ignore"
|
||||||
|
|
||||||
|
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]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
SetWebUITheme() {
|
||||||
|
change_setting "WEBTHEME" "${args[2]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckUrl(){
|
||||||
|
local regex check_url
|
||||||
|
# Check for characters NOT allowed in URLs
|
||||||
|
regex="[^a-zA-Z0-9:/?&%=~._()-;]"
|
||||||
|
|
||||||
|
# this will remove first @ that is after schema and before domain
|
||||||
|
# \1 is optional schema, \2 is userinfo
|
||||||
|
check_url="$( sed -re 's#([^:/]*://)?([^/]+)@#\1\2#' <<< "$1" )"
|
||||||
|
|
||||||
|
if [[ "${check_url}" =~ ${regex} ]]; then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomizeAdLists() {
|
||||||
|
local address
|
||||||
|
address="${args[3]}"
|
||||||
|
local comment
|
||||||
|
comment="${args[4]}"
|
||||||
|
|
||||||
|
if CheckUrl "${address}"; then
|
||||||
|
if [[ "${args[2]}" == "enable" ]]; then
|
||||||
|
sqlite3 "${gravityDBfile}" "UPDATE adlist SET enabled = 1 WHERE address = '${address}'"
|
||||||
|
elif [[ "${args[2]}" == "disable" ]]; then
|
||||||
|
sqlite3 "${gravityDBfile}" "UPDATE adlist SET enabled = 0 WHERE address = '${address}'"
|
||||||
|
elif [[ "${args[2]}" == "add" ]]; then
|
||||||
|
sqlite3 "${gravityDBfile}" "INSERT OR IGNORE INTO adlist (address, comment) VALUES ('${address}', '${comment}')"
|
||||||
|
elif [[ "${args[2]}" == "del" ]]; then
|
||||||
|
sqlite3 "${gravityDBfile}" "DELETE FROM adlist WHERE address = '${address}'"
|
||||||
|
else
|
||||||
|
echo "Not permitted"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Invalid Url"
|
||||||
|
return 1
|
||||||
|
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]}"
|
||||||
|
if [[ "$mac" =~ ^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$ ]]; then
|
||||||
|
sed -i "/dhcp-host=${mac}.*/d" "${dhcpstaticconfig}"
|
||||||
|
else
|
||||||
|
echo " ${CROSS} Invalid Mac Passed!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SetAdminEmail() {
|
||||||
|
if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]]; then
|
||||||
|
echo "Usage: pihole -a email <address>
|
||||||
|
Example: 'pihole -a email admin@address.com'
|
||||||
|
Set an administrative contact address for the Block Page
|
||||||
|
|
||||||
|
Options:
|
||||||
|
\"\" Empty: Remove admin contact
|
||||||
|
-h, --help Show this help dialog"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "${args[2]}" ]]; then
|
||||||
|
|
||||||
|
# Sanitize email address in case of security issues
|
||||||
|
# Regex from https://stackoverflow.com/a/2138832/4065967
|
||||||
|
local regex
|
||||||
|
regex="^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\$"
|
||||||
|
if [[ ! "${args[2]}" =~ ${regex} ]]; then
|
||||||
|
echo -e " ${CROSS} Invalid email address"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
change_setting "ADMIN_EMAIL" "${args[2]}"
|
||||||
|
echo -e " ${TICK} Setting admin contact to ${args[2]}"
|
||||||
|
else
|
||||||
|
change_setting "ADMIN_EMAIL" ""
|
||||||
|
echo -e " ${TICK} Removing admin contact"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Only respond to queries from devices that
|
||||||
|
are at most one hop away (local devices)
|
||||||
|
single Respond only on interface ${PIHOLE_INTERFACE}
|
||||||
|
bind Bind only on interface ${PIHOLE_INTERFACE}
|
||||||
|
all Listen on all interfaces, permit all origins"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${args[2]}" == "all" ]]; then
|
||||||
|
echo -e " ${INFO} Listening on all interfaces, permitting all origins. Please use a firewall!"
|
||||||
|
change_setting "DNSMASQ_LISTENING" "all"
|
||||||
|
elif [[ "${args[2]}" == "local" ]]; then
|
||||||
|
echo -e " ${INFO} Listening on all interfaces, permitting origins from one hop away (LAN)"
|
||||||
|
change_setting "DNSMASQ_LISTENING" "local"
|
||||||
|
elif [[ "${args[2]}" == "bind" ]]; then
|
||||||
|
echo -e " ${INFO} Binding on interface ${PIHOLE_INTERFACE}"
|
||||||
|
change_setting "DNSMASQ_LISTENING" "bind"
|
||||||
|
else
|
||||||
|
echo -e " ${INFO} 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
|
||||||
|
local host
|
||||||
|
datetimestamp=$(date "+%Y-%m-%d_%H-%M-%S")
|
||||||
|
host=$(hostname)
|
||||||
|
host="${host//./_}"
|
||||||
|
php /var/www/html/admin/scripts/pi-hole/php/teleporter.php > "pi-hole-${host:-noname}-teleporter_${datetimestamp}.tar.gz"
|
||||||
|
}
|
||||||
|
|
||||||
|
checkDomain()
|
||||||
|
{
|
||||||
|
local domain validDomain
|
||||||
|
# Convert to lowercase
|
||||||
|
domain="${1,,}"
|
||||||
|
validDomain=$(grep -P "^((-|_)*[a-z\\d]((-|_)*[a-z\\d])*(-|_)*)(\\.(-|_)*([a-z\\d]((-|_)*[a-z\\d])*))*$" <<< "${domain}") # Valid chars check
|
||||||
|
validDomain=$(grep -P "^[^\\.]{1,63}(\\.[^\\.]{1,63})*$" <<< "${validDomain}") # Length of each label
|
||||||
|
echo "${validDomain}"
|
||||||
|
}
|
||||||
|
|
||||||
|
addAudit()
|
||||||
|
{
|
||||||
|
shift # skip "-a"
|
||||||
|
shift # skip "audit"
|
||||||
|
local domains validDomain
|
||||||
|
domains=""
|
||||||
|
for domain in "$@"
|
||||||
|
do
|
||||||
|
# Check domain to be added. Only continue if it is valid
|
||||||
|
validDomain="$(checkDomain "${domain}")"
|
||||||
|
if [[ -n "${validDomain}" ]]; then
|
||||||
|
# Put comma in between domains when there is
|
||||||
|
# more than one domains to be added
|
||||||
|
# SQL INSERT allows adding multiple rows at once using the format
|
||||||
|
## INSERT INTO table (domain) VALUES ('abc.de'),('fgh.ij'),('klm.no'),('pqr.st');
|
||||||
|
if [[ -n "${domains}" ]]; then
|
||||||
|
domains="${domains},"
|
||||||
|
fi
|
||||||
|
domains="${domains}('${domain}')"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# Insert only the domain here. The date_added field will be
|
||||||
|
# filled with its default value (date_added = current timestamp)
|
||||||
|
sqlite3 "${gravityDBfile}" "INSERT INTO domain_audit (domain) VALUES ${domains};"
|
||||||
|
}
|
||||||
|
|
||||||
|
clearAudit()
|
||||||
|
{
|
||||||
|
sqlite3 "${gravityDBfile}" "DELETE FROM domain_audit;"
|
||||||
|
}
|
||||||
|
|
||||||
|
SetPrivacyLevel() {
|
||||||
|
# Set privacy level. Minimum is 0, maximum is 3
|
||||||
|
if [ "${args[2]}" -ge 0 ] && [ "${args[2]}" -le 3 ]; then
|
||||||
|
changeFTLsetting "PRIVACYLEVEL" "${args[2]}"
|
||||||
|
pihole restartdns reload-lists
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
AddCustomDNSAddress() {
|
||||||
|
echo -e " ${TICK} Adding custom DNS entry..."
|
||||||
|
|
||||||
|
ip="${args[2]}"
|
||||||
|
host="${args[3]}"
|
||||||
|
reload="${args[4]}"
|
||||||
|
|
||||||
|
validHost="$(checkDomain "${host}")"
|
||||||
|
if [[ -n "${validHost}" ]]; then
|
||||||
|
if valid_ip "${ip}" || valid_ip6 "${ip}" ; then
|
||||||
|
echo "${ip} ${validHost}" >> "${dnscustomfile}"
|
||||||
|
else
|
||||||
|
echo -e " ${CROSS} Invalid IP has been passed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " ${CROSS} Invalid Domain passed!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Restart dnsmasq to load new custom DNS entries only if $reload not false
|
||||||
|
if [[ ! $reload == "false" ]]; then
|
||||||
|
RestartDNS
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveCustomDNSAddress() {
|
||||||
|
echo -e " ${TICK} Removing custom DNS entry..."
|
||||||
|
|
||||||
|
ip="${args[2]}"
|
||||||
|
host="${args[3]}"
|
||||||
|
reload="${args[4]}"
|
||||||
|
|
||||||
|
validHost="$(checkDomain "${host}")"
|
||||||
|
if [[ -n "${validHost}" ]]; then
|
||||||
|
if valid_ip "${ip}" || valid_ip6 "${ip}" ; then
|
||||||
|
sed -i "/^${ip} ${validHost}$/d" "${dnscustomfile}"
|
||||||
|
else
|
||||||
|
echo -e " ${CROSS} Invalid IP has been passed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " ${CROSS} Invalid Domain passed!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Restart dnsmasq to load new custom DNS entries only if reload is not false
|
||||||
|
if [[ ! $reload == "false" ]]; then
|
||||||
|
RestartDNS
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
AddCustomCNAMERecord() {
|
||||||
|
echo -e " ${TICK} Adding custom CNAME record..."
|
||||||
|
|
||||||
|
domain="${args[2]}"
|
||||||
|
target="${args[3]}"
|
||||||
|
reload="${args[4]}"
|
||||||
|
|
||||||
|
validDomain="$(checkDomain "${domain}")"
|
||||||
|
if [[ -n "${validDomain}" ]]; then
|
||||||
|
validTarget="$(checkDomain "${target}")"
|
||||||
|
if [[ -n "${validTarget}" ]]; then
|
||||||
|
echo "cname=${validDomain},${validTarget}" >> "${dnscustomcnamefile}"
|
||||||
|
else
|
||||||
|
echo " ${CROSS} Invalid Target Passed!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " ${CROSS} Invalid Domain passed!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# Restart dnsmasq to load new custom CNAME records only if reload is not false
|
||||||
|
if [[ ! $reload == "false" ]]; then
|
||||||
|
RestartDNS
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveCustomCNAMERecord() {
|
||||||
|
echo -e " ${TICK} Removing custom CNAME record..."
|
||||||
|
|
||||||
|
domain="${args[2]}"
|
||||||
|
target="${args[3]}"
|
||||||
|
reload="${args[4]}"
|
||||||
|
|
||||||
|
validDomain="$(checkDomain "${domain}")"
|
||||||
|
if [[ -n "${validDomain}" ]]; then
|
||||||
|
validTarget="$(checkDomain "${target}")"
|
||||||
|
if [[ -n "${validTarget}" ]]; then
|
||||||
|
sed -i "/cname=${validDomain},${validTarget}$/d" "${dnscustomcnamefile}"
|
||||||
|
else
|
||||||
|
echo " ${CROSS} Invalid Target Passed!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " ${CROSS} Invalid Domain passed!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Restart dnsmasq to update removed custom CNAME records only if $reload not false
|
||||||
|
if [[ ! $reload == "false" ]]; then
|
||||||
|
RestartDNS
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
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;;
|
||||||
|
"poweroff" ) Poweroff;;
|
||||||
|
"reboot" ) Reboot;;
|
||||||
|
"restartdns" ) RestartDNS;;
|
||||||
|
"setquerylog" ) SetQueryLogOptions;;
|
||||||
|
"enabledhcp" ) EnableDHCP;;
|
||||||
|
"disabledhcp" ) DisableDHCP;;
|
||||||
|
"layout" ) SetWebUILayout;;
|
||||||
|
"theme" ) SetWebUITheme;;
|
||||||
|
"-h" | "--help" ) helpFunc;;
|
||||||
|
"addstaticdhcp" ) AddDHCPStaticAddress;;
|
||||||
|
"removestaticdhcp" ) RemoveDHCPStaticAddress;;
|
||||||
|
"-e" | "email" ) SetAdminEmail "$3";;
|
||||||
|
"-i" | "interface" ) SetListeningMode "$@";;
|
||||||
|
"-t" | "teleporter" ) Teleporter;;
|
||||||
|
"adlist" ) CustomizeAdLists;;
|
||||||
|
"audit" ) addAudit "$@";;
|
||||||
|
"clearaudit" ) clearAudit;;
|
||||||
|
"-l" | "privacylevel" ) SetPrivacyLevel;;
|
||||||
|
"addcustomdns" ) AddCustomDNSAddress;;
|
||||||
|
"removecustomdns" ) RemoveCustomDNSAddress;;
|
||||||
|
"addcustomcname" ) AddCustomCNAMERecord;;
|
||||||
|
"removecustomcname" ) RemoveCustomCNAMERecord;;
|
||||||
|
* ) helpFunc;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
shift
|
||||||
|
|
||||||
|
if [[ $# = 0 ]]; then
|
||||||
|
helpFunc
|
||||||
|
fi
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# For each argument passed to this script
|
|
||||||
for var in "$@"
|
|
||||||
do
|
|
||||||
echo "Whitelisting $var..."
|
|
||||||
# Use sed to search for the domain in /etc/pihole/gravity.list and remove it using an in-place edit
|
|
||||||
sed -i "/$var/d" /etc/pihole/gravity.list
|
|
||||||
# Also add the domain to the whitelist.txt in /etc/pihole
|
|
||||||
echo "$var" >> /etc/pihole/whitelist.txt
|
|
||||||
done
|
|
||||||
echo "** $# domain(s) whitelisted."
|
|
||||||
# Force dnsmasq to reload /etc/pihole/gravity.list
|
|
||||||
kill -HUP $(pidof dnsmasq)
|
|
||||||
191
advanced/Templates/gravity.db.sql
Normal file
191
advanced/Templates/gravity.db.sql
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
PRAGMA foreign_keys=OFF;
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
CREATE TABLE "group"
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
enabled BOOLEAN NOT NULL DEFAULT 1,
|
||||||
|
name TEXT UNIQUE NOT NULL,
|
||||||
|
date_added INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||||
|
date_modified INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||||
|
description TEXT
|
||||||
|
);
|
||||||
|
INSERT INTO "group" (id,enabled,name,description) VALUES (0,1,'Default','The default group');
|
||||||
|
|
||||||
|
CREATE TABLE domainlist
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
type INTEGER NOT NULL DEFAULT 0,
|
||||||
|
domain TEXT NOT NULL,
|
||||||
|
enabled BOOLEAN NOT NULL DEFAULT 1,
|
||||||
|
date_added INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||||
|
date_modified INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||||
|
comment TEXT,
|
||||||
|
UNIQUE(domain, type)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE adlist
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
address TEXT UNIQUE NOT NULL,
|
||||||
|
enabled BOOLEAN NOT NULL DEFAULT 1,
|
||||||
|
date_added INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||||
|
date_modified INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||||
|
comment TEXT,
|
||||||
|
date_updated INTEGER,
|
||||||
|
number INTEGER NOT NULL DEFAULT 0,
|
||||||
|
invalid_domains INTEGER NOT NULL DEFAULT 0,
|
||||||
|
status INTEGER NOT NULL DEFAULT 0
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE adlist_by_group
|
||||||
|
(
|
||||||
|
adlist_id INTEGER NOT NULL REFERENCES adlist (id),
|
||||||
|
group_id INTEGER NOT NULL REFERENCES "group" (id),
|
||||||
|
PRIMARY KEY (adlist_id, group_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE gravity
|
||||||
|
(
|
||||||
|
domain TEXT NOT NULL,
|
||||||
|
adlist_id INTEGER NOT NULL REFERENCES adlist (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE info
|
||||||
|
(
|
||||||
|
property TEXT PRIMARY KEY,
|
||||||
|
value TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO "info" VALUES('version','15');
|
||||||
|
|
||||||
|
CREATE TABLE domain_audit
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
domain TEXT UNIQUE NOT NULL,
|
||||||
|
date_added INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int))
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE domainlist_by_group
|
||||||
|
(
|
||||||
|
domainlist_id INTEGER NOT NULL REFERENCES domainlist (id),
|
||||||
|
group_id INTEGER NOT NULL REFERENCES "group" (id),
|
||||||
|
PRIMARY KEY (domainlist_id, group_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE client
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
ip TEXT NOT NULL UNIQUE,
|
||||||
|
date_added INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||||
|
date_modified INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)),
|
||||||
|
comment TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE client_by_group
|
||||||
|
(
|
||||||
|
client_id INTEGER NOT NULL REFERENCES client (id),
|
||||||
|
group_id INTEGER NOT NULL REFERENCES "group" (id),
|
||||||
|
PRIMARY KEY (client_id, group_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_adlist_update AFTER UPDATE OF address,enabled,comment ON adlist
|
||||||
|
BEGIN
|
||||||
|
UPDATE adlist SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE id = NEW.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_client_update AFTER UPDATE ON client
|
||||||
|
BEGIN
|
||||||
|
UPDATE client SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE ip = NEW.ip;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_domainlist_update AFTER UPDATE ON domainlist
|
||||||
|
BEGIN
|
||||||
|
UPDATE domainlist SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE domain = NEW.domain;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE VIEW vw_whitelist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
||||||
|
FROM domainlist
|
||||||
|
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
||||||
|
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
||||||
|
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
||||||
|
AND domainlist.type = 0
|
||||||
|
ORDER BY domainlist.id;
|
||||||
|
|
||||||
|
CREATE VIEW vw_blacklist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
||||||
|
FROM domainlist
|
||||||
|
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
||||||
|
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
||||||
|
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
||||||
|
AND domainlist.type = 1
|
||||||
|
ORDER BY domainlist.id;
|
||||||
|
|
||||||
|
CREATE VIEW vw_regex_whitelist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
||||||
|
FROM domainlist
|
||||||
|
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
||||||
|
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
||||||
|
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
||||||
|
AND domainlist.type = 2
|
||||||
|
ORDER BY domainlist.id;
|
||||||
|
|
||||||
|
CREATE VIEW vw_regex_blacklist AS SELECT domain, domainlist.id AS id, domainlist_by_group.group_id AS group_id
|
||||||
|
FROM domainlist
|
||||||
|
LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id
|
||||||
|
LEFT JOIN "group" ON "group".id = domainlist_by_group.group_id
|
||||||
|
WHERE domainlist.enabled = 1 AND (domainlist_by_group.group_id IS NULL OR "group".enabled = 1)
|
||||||
|
AND domainlist.type = 3
|
||||||
|
ORDER BY domainlist.id;
|
||||||
|
|
||||||
|
CREATE VIEW vw_gravity AS SELECT domain, adlist_by_group.group_id AS group_id
|
||||||
|
FROM gravity
|
||||||
|
LEFT JOIN adlist_by_group ON adlist_by_group.adlist_id = gravity.adlist_id
|
||||||
|
LEFT JOIN adlist ON adlist.id = gravity.adlist_id
|
||||||
|
LEFT JOIN "group" ON "group".id = adlist_by_group.group_id
|
||||||
|
WHERE adlist.enabled = 1 AND (adlist_by_group.group_id IS NULL OR "group".enabled = 1);
|
||||||
|
|
||||||
|
CREATE VIEW vw_adlist AS SELECT DISTINCT address, id
|
||||||
|
FROM adlist
|
||||||
|
WHERE enabled = 1
|
||||||
|
ORDER BY id;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_domainlist_add AFTER INSERT ON domainlist
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO domainlist_by_group (domainlist_id, group_id) VALUES (NEW.id, 0);
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_client_add AFTER INSERT ON client
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO client_by_group (client_id, group_id) VALUES (NEW.id, 0);
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_adlist_add AFTER INSERT ON adlist
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO adlist_by_group (adlist_id, group_id) VALUES (NEW.id, 0);
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_group_update AFTER UPDATE ON "group"
|
||||||
|
BEGIN
|
||||||
|
UPDATE "group" SET date_modified = (cast(strftime('%s', 'now') as int)) WHERE id = NEW.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_group_zero AFTER DELETE ON "group"
|
||||||
|
BEGIN
|
||||||
|
INSERT OR IGNORE INTO "group" (id,enabled,name) VALUES (0,1,'Default');
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_domainlist_delete AFTER DELETE ON domainlist
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM domainlist_by_group WHERE domainlist_id = OLD.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_adlist_delete AFTER DELETE ON adlist
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM adlist_by_group WHERE adlist_id = OLD.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_client_delete AFTER DELETE ON client
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM client_by_group WHERE client_id = OLD.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
42
advanced/Templates/gravity_copy.sql
Normal file
42
advanced/Templates/gravity_copy.sql
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
.timeout 30000
|
||||||
|
|
||||||
|
ATTACH DATABASE '/etc/pihole/gravity.db' AS OLD;
|
||||||
|
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
DROP TRIGGER tr_domainlist_add;
|
||||||
|
DROP TRIGGER tr_client_add;
|
||||||
|
DROP TRIGGER tr_adlist_add;
|
||||||
|
|
||||||
|
INSERT OR REPLACE INTO "group" SELECT * FROM OLD."group";
|
||||||
|
INSERT OR REPLACE INTO domain_audit SELECT * FROM OLD.domain_audit;
|
||||||
|
|
||||||
|
INSERT OR REPLACE INTO domainlist SELECT * FROM OLD.domainlist;
|
||||||
|
INSERT OR REPLACE INTO domainlist_by_group SELECT * FROM OLD.domainlist_by_group;
|
||||||
|
|
||||||
|
INSERT OR REPLACE INTO adlist SELECT * FROM OLD.adlist;
|
||||||
|
INSERT OR REPLACE INTO adlist_by_group SELECT * FROM OLD.adlist_by_group;
|
||||||
|
|
||||||
|
INSERT OR REPLACE INTO info SELECT * FROM OLD.info;
|
||||||
|
|
||||||
|
INSERT OR REPLACE INTO client SELECT * FROM OLD.client;
|
||||||
|
INSERT OR REPLACE INTO client_by_group SELECT * FROM OLD.client_by_group;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_domainlist_add AFTER INSERT ON domainlist
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO domainlist_by_group (domainlist_id, group_id) VALUES (NEW.id, 0);
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_client_add AFTER INSERT ON client
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO client_by_group (client_id, group_id) VALUES (NEW.id, 0);
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr_adlist_add AFTER INSERT ON adlist
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO adlist_by_group (adlist_id, group_id) VALUES (NEW.id, 0);
|
||||||
|
END;
|
||||||
|
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
21
advanced/Templates/logrotate
Normal file
21
advanced/Templates/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
|
||||||
|
}
|
||||||
2
advanced/Templates/pihole-FTL.conf
Normal file
2
advanced/Templates/pihole-FTL.conf
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#; Pi-hole FTL config file
|
||||||
|
#; Comments should start with #; to avoid issues with PHP and bash reading this file
|
||||||
102
advanced/Templates/pihole-FTL.service
Normal file
102
advanced/Templates/pihole-FTL.service
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
### BEGIN INIT INFO
|
||||||
|
# Provides: pihole-FTL
|
||||||
|
# Required-Start: $remote_fs $syslog $network
|
||||||
|
# Required-Stop: $remote_fs $syslog $network
|
||||||
|
# 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
|
||||||
|
|
||||||
|
is_running() {
|
||||||
|
pgrep -xo "pihole-FTL" > /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Start the service
|
||||||
|
start() {
|
||||||
|
if is_running; then
|
||||||
|
echo "pihole-FTL is already running"
|
||||||
|
else
|
||||||
|
# Touch files to ensure they exist (create if non-existing, preserve if existing)
|
||||||
|
mkdir -pm 0755 /run/pihole
|
||||||
|
touch /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole-FTL.log /var/log/pihole.log /etc/pihole/dhcp.leases
|
||||||
|
# Ensure that permissions are set so that pihole-FTL can edit all necessary files
|
||||||
|
chown pihole:pihole /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole-FTL.log /var/log/pihole.log /etc/pihole/dhcp.leases /run/pihole /etc/pihole
|
||||||
|
chmod 0644 /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole-FTL.log /var/log/pihole.log /etc/pihole/dhcp.leases
|
||||||
|
# Ensure that permissions are set so that pihole-FTL can edit the files. We ignore errors as the file may not (yet) exist
|
||||||
|
chmod -f 0644 /etc/pihole/macvendor.db
|
||||||
|
# Chown database files to the user FTL runs as. We ignore errors as the files may not (yet) exist
|
||||||
|
chown -f pihole:pihole /etc/pihole/pihole-FTL.db /etc/pihole/gravity.db /etc/pihole/macvendor.db
|
||||||
|
# Chown database file permissions so that the pihole group (web interface) can edit the file. We ignore errors as the files may not (yet) exist
|
||||||
|
chmod -f 0664 /etc/pihole/pihole-FTL.db
|
||||||
|
if setcap CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_NET_ADMIN,CAP_SYS_NICE,CAP_IPC_LOCK,CAP_CHOWN+eip "/usr/bin/pihole-FTL"; then
|
||||||
|
su -s /bin/sh -c "/usr/bin/pihole-FTL" pihole
|
||||||
|
else
|
||||||
|
echo "Warning: Starting pihole-FTL as root because setting capabilities is not supported on this system"
|
||||||
|
/usr/bin/pihole-FTL
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Stop the service
|
||||||
|
stop() {
|
||||||
|
if is_running; then
|
||||||
|
pkill -xo "pihole-FTL"
|
||||||
|
for i in 1 2 3 4 5; do
|
||||||
|
if ! is_running; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "."
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
|
||||||
|
if is_running; then
|
||||||
|
echo "Not stopped; may still be shutting down or shutdown may have failed, killing now"
|
||||||
|
pkill -xo -9 "pihole-FTL"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "Stopped"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Not running"
|
||||||
|
fi
|
||||||
|
# Cleanup
|
||||||
|
rm -f /run/pihole/FTL.sock /dev/shm/FTL-*
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
# Indicate the service status
|
||||||
|
status() {
|
||||||
|
if is_running; then
|
||||||
|
echo "[ ok ] pihole-FTL is running"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "[ ] pihole-FTL is not running"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
### main logic ###
|
||||||
|
case "$1" in
|
||||||
|
stop)
|
||||||
|
stop
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
status
|
||||||
|
;;
|
||||||
|
start|restart|reload|condrestart)
|
||||||
|
stop
|
||||||
|
start
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 {start|stop|restart|reload|status}"
|
||||||
|
exit 1
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
||||||
36
advanced/Templates/pihole.cron
Normal file
36
advanced/Templates/pihole.cron
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# 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 software
|
||||||
|
# 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 a random time in the
|
||||||
|
# early morning. Download any updates from the adlists
|
||||||
|
# Squash output to log, then splat the log to stdout on error to allow for
|
||||||
|
# standard crontab job error handling.
|
||||||
|
59 1 * * 7 root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updateGravity >/var/log/pihole_updateGravity.log || cat /var/log/pihole_updateGravity.log
|
||||||
|
|
||||||
|
# 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/sbin:/usr/local/bin/" pihole flush once quiet
|
||||||
|
|
||||||
|
@reboot root /usr/sbin/logrotate --state /var/lib/logrotate/pihole /etc/pihole/logrotate
|
||||||
|
|
||||||
|
# Pi-hole: Grab local version and branch every 10 minutes
|
||||||
|
*/10 * * * * root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updatechecker local
|
||||||
|
|
||||||
|
# Pi-hole: Grab remote version every 24 hours
|
||||||
|
59 17 * * * root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updatechecker remote
|
||||||
|
@reboot root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updatechecker remote reboot
|
||||||
9
advanced/Templates/pihole.sudo
Normal file
9
advanced/Templates/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.
|
||||||
|
#
|
||||||
79
advanced/bash-completion/pihole
Normal file
79
advanced/bash-completion/pihole
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
_pihole() {
|
||||||
|
local cur prev opts opts_admin opts_checkout opts_chronometer opts_debug opts_interface opts_logging opts_privacy opts_query opts_update opts_version
|
||||||
|
COMPREPLY=()
|
||||||
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||||
|
prev2="${COMP_WORDS[COMP_CWORD-2]}"
|
||||||
|
|
||||||
|
case "${prev}" in
|
||||||
|
"pihole")
|
||||||
|
opts="admin blacklist checkout chronometer debug disable enable flush help logging query reconfigure regex restartdns status tail uninstall updateGravity updatePihole version wildcard whitelist arpflush"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"whitelist"|"blacklist"|"wildcard"|"regex")
|
||||||
|
opts_lists="\--delmode \--noreload \--quiet \--list \--nuke"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_lists}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"admin")
|
||||||
|
opts_admin="celsius email fahrenheit interface kelvin password privacylevel"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_admin}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"checkout")
|
||||||
|
opts_checkout="core ftl web master dev"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_checkout}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"chronometer")
|
||||||
|
opts_chronometer="\--exit \--json \--refresh"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_chronometer}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"debug")
|
||||||
|
opts_debug="-a"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_debug}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"logging")
|
||||||
|
opts_logging="on off 'off noflush'"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_logging}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"query")
|
||||||
|
opts_query="-adlist -all -exact"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_query}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"updatePihole"|"-up")
|
||||||
|
opts_update="--check-only"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_update}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"version")
|
||||||
|
opts_version="\--admin \--current \--ftl \--hash \--latest \--pihole"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_version}" -- ${cur}) )
|
||||||
|
;;
|
||||||
|
"interface")
|
||||||
|
if ( [[ "$prev2" == "admin" ]] || [[ "$prev2" == "-a" ]] ); then
|
||||||
|
opts_interface="$(cat /proc/net/dev | cut -d: -s -f1)"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_interface}" -- ${cur}) )
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"privacylevel")
|
||||||
|
if ( [[ "$prev2" == "admin" ]] || [[ "$prev2" == "-a" ]] ); then
|
||||||
|
opts_privacy="0 1 2 3"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_privacy}" -- ${cur}) )
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"core"|"admin"|"ftl")
|
||||||
|
if [[ "$prev2" == "checkout" ]]; then
|
||||||
|
opts_checkout="master dev"
|
||||||
|
COMPREPLY=( $(compgen -W "${opts_checkout}" -- ${cur}) )
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
complete -F _pihole pihole
|
||||||
455
advanced/blockingpage.css
Normal file
455
advanced/blockingpage.css
Normal file
@@ -0,0 +1,455 @@
|
|||||||
|
/* Pi-hole: A black hole for Internet advertisements
|
||||||
|
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||||
|
* Network-wide ad blocking via your own hardware.
|
||||||
|
*
|
||||||
|
* This file is copyright under the latest version of the EUPL.
|
||||||
|
* Please see LICENSE file for your rights under this license. */
|
||||||
|
|
||||||
|
/* Text Customisation Options ======> */
|
||||||
|
.title::before { content: "Website Blocked"; }
|
||||||
|
.altBtn::before { content: "Why am I here?"; }
|
||||||
|
.linkPH::before { content: "About Pi-hole"; }
|
||||||
|
.linkEmail::before { content: "Contact Admin"; }
|
||||||
|
|
||||||
|
#bpOutput.add::before { content: "Info"; }
|
||||||
|
#bpOutput.add::after { content: "The domain is being whitelisted..."; }
|
||||||
|
#bpOutput.error::before, .unhandled::before { content: "Error"; }
|
||||||
|
#bpOutput.unhandled::after { content: "An unhandled exception occurred. This may happen when your browser is unable to load jQuery, or when the webserver is denying access to the Pi-hole API."; }
|
||||||
|
#bpOutput.success::before { content: "Success"; }
|
||||||
|
#bpOutput.success::after { content: "Website has been whitelisted! You may need to flush your DNS cache"; }
|
||||||
|
|
||||||
|
.recentwl::before { content: "This site has been whitelisted. Please flush your DNS cache and/or restart your browser."; }
|
||||||
|
.unknown::before { content: "This website is not found in any of Pi-hole's blacklists. The reason you have arrived here is unknown."; }
|
||||||
|
.cname::before { content: "This site is an alias for "; } /* <a href="http://cname.com">cname.com</a> */
|
||||||
|
.cname::after { content: ", which may be blocked by Pi-hole."; }
|
||||||
|
|
||||||
|
.blacklist::before { content: "Manually Blacklisted"; }
|
||||||
|
.wildcard::before { content: "Manually Blacklisted by Wildcard"; }
|
||||||
|
.noblock::before { content: "Not found on any Blacklist"; }
|
||||||
|
|
||||||
|
#bpBlock::before { content: "Access to the following website has been denied:"; }
|
||||||
|
#bpFlag::before { content: "This is primarily due to being flagged as:"; }
|
||||||
|
|
||||||
|
#bpHelpTxt::before { content: "If you have an ongoing use for this website, please "; }
|
||||||
|
#bpHelpTxt a::before, #bpHelpTxt span::before { content: "ask the administrator"; }
|
||||||
|
#bpHelpTxt::after{ content: " of the Pi-hole on this network to have it whitelisted"; }
|
||||||
|
|
||||||
|
#bpBack::before { content: "Back to safety"; }
|
||||||
|
#bpInfo::before { content: "Technical Info"; }
|
||||||
|
#bpFoundIn::before { content: "This site is found in "; }
|
||||||
|
#bpFoundIn span::after { content: " of "; }
|
||||||
|
#bpFoundIn::after { content: " lists:"; }
|
||||||
|
#bpWhitelist::before { content: "Whitelist"; }
|
||||||
|
|
||||||
|
footer span::before { content: "Page generated on "; }
|
||||||
|
|
||||||
|
/* Hide whitelisting form entirely */
|
||||||
|
/* #bpWLButtons { display: none; } */
|
||||||
|
|
||||||
|
/* Text Customisation Options <=============================== */
|
||||||
|
|
||||||
|
/* http://necolas.github.io/normalize.css ======> */
|
||||||
|
html { font-family: sans-serif; line-height: 1.15; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; }
|
||||||
|
body { margin: 0; }
|
||||||
|
article, aside, footer, header, nav, section { display: block; }
|
||||||
|
h1 { font-size: 2em; margin: 0.67em 0; }
|
||||||
|
figcaption, figure, main { display: block; }
|
||||||
|
figure { margin: 1em 40px; }
|
||||||
|
hr { box-sizing: content-box; height: 0; overflow: visible; }
|
||||||
|
pre { font-family: monospace, monospace; font-size: 1em; }
|
||||||
|
a { background-color: transparent; -webkit-text-decoration-skip: objects; }
|
||||||
|
a:active, a:hover { outline-width: 0; }
|
||||||
|
abbr[title] { border-bottom: none; text-decoration: underline; text-decoration: underline dotted; }
|
||||||
|
b, strong { font-weight: inherit; }
|
||||||
|
b, strong { font-weight: bolder; }
|
||||||
|
code, kbd, samp { font-family: monospace, monospace; font-size: 1em; }
|
||||||
|
dfn { font-style: italic; }
|
||||||
|
mark { background-color: #ff0; color: #000; }
|
||||||
|
small { font-size: 80%; }
|
||||||
|
sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }
|
||||||
|
sub { bottom: -0.25em; }
|
||||||
|
sup { top: -0.5em; }
|
||||||
|
audio, video { display: inline-block; }
|
||||||
|
audio:not([controls]) { display: none; height: 0; }
|
||||||
|
img { border-style: none; }
|
||||||
|
svg:not(:root) { overflow: hidden; }
|
||||||
|
button, input, optgroup, select, textarea { font-family: sans-serif; font-size: 100%; line-height: 1.15; margin: 0; }
|
||||||
|
button, input { overflow: visible; }
|
||||||
|
button, select { text-transform: none; }
|
||||||
|
button, html [type="button"], [type="reset"], [type="submit"] { -webkit-appearance: button; }
|
||||||
|
button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner { border-style: none; padding: 0; }
|
||||||
|
button:-moz-focusring, [type="button"]:-moz-focusring, [type="reset"]:-moz-focusring, [type="submit"]:-moz-focusring { outline: 1px dotted ButtonText; }
|
||||||
|
fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; }
|
||||||
|
legend { box-sizing: border-box; color: inherit; display: table; max-width: 100%; padding: 0; white-space: normal; }
|
||||||
|
progress { display: inline-block; vertical-align: baseline; }
|
||||||
|
textarea { overflow: auto; }
|
||||||
|
[type="checkbox"], [type="radio"] { box-sizing: border-box; padding: 0; }
|
||||||
|
[type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button { height: auto; }
|
||||||
|
[type="search"] { -webkit-appearance: textfield; outline-offset: -2px; }
|
||||||
|
[type="search"]::-webkit-search-cancel-button, [type="search"]::-webkit-search-decoration { -webkit-appearance: none; }
|
||||||
|
::-webkit-file-upload-button { -webkit-appearance: button; font: inherit; }
|
||||||
|
details, menu { display: block; }
|
||||||
|
summary { display: list-item; }
|
||||||
|
canvas { display: inline-block; }
|
||||||
|
template { display: none; }
|
||||||
|
[hidden] { display: none; }
|
||||||
|
/* Normalize.css <=============================== */
|
||||||
|
|
||||||
|
html { font-size: 62.5%; }
|
||||||
|
|
||||||
|
a { color: #3c8dbc; text-decoration: none; }
|
||||||
|
a:hover { color: #72afda; text-decoration: underline; }
|
||||||
|
b { color: rgb(68, 68, 68); }
|
||||||
|
p { margin: 0; }
|
||||||
|
|
||||||
|
label, .buttons a {
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
label, .buttons *:not([disabled]) { cursor: pointer; }
|
||||||
|
|
||||||
|
/* Touch device dark tap highlight */
|
||||||
|
header h1 a, label, .buttons * { -webkit-tap-highlight-color: transparent; }
|
||||||
|
|
||||||
|
/* Webkit Focus Glow */
|
||||||
|
textarea, input, button { outline: none; }
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Source Sans Pro";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: local("Source Sans Pro Regular"), local("SourceSansPro-Regular"),
|
||||||
|
url("/admin/style/vendor/SourceSansPro/source-sans-pro-v13-latin-regular.woff2") format("woff2"),
|
||||||
|
url("/admin/style/vendor/SourceSansPro/source-sans-pro-v13-latin-regular.woff") format("woff");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Source Sans Pro";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: local("Source Sans Pro Bold"), local("SourceSansPro-Bold"),
|
||||||
|
url("/admin/style/vendor/SourceSansPro/source-sans-pro-v13-latin-700.woff2") format("woff2"),
|
||||||
|
url("/admin/style/vendor/SourceSansPro/source-sans-pro-v13-latin-700.woff") format("woff");
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: #dbdbdb url("/admin/img/boxed-bg.jpg") repeat fixed;
|
||||||
|
color: #333;
|
||||||
|
font: 1.4rem "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
line-height: 2.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* User is greeted with a splash page when browsing to Pi-hole IP address */
|
||||||
|
#splashpage {
|
||||||
|
background: #222;
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#splashpage img { margin: 5px; width: 256px; }
|
||||||
|
#splashpage b { color: inherit; }
|
||||||
|
|
||||||
|
#bpWrapper {
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 1250px;
|
||||||
|
box-shadow: 0 0 8px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
background: #3c8dbc;
|
||||||
|
display: table;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
header h1, header h1 a, header .spc, header #bpAlt label {
|
||||||
|
display: table-cell;
|
||||||
|
color: #fff;
|
||||||
|
white-space: nowrap;
|
||||||
|
vertical-align: middle;
|
||||||
|
height: 50px; /* Must match #bpAbout top value */
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 a {
|
||||||
|
background-color: rgba(0, 0, 0, 0.1);
|
||||||
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 400;
|
||||||
|
min-width: 230px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 a:hover, header #bpAlt:hover { background-color: rgba(0, 0, 0, 0.12); color: inherit; text-decoration: none; }
|
||||||
|
|
||||||
|
header .spc { width: 100%; }
|
||||||
|
|
||||||
|
header #bpAlt label {
|
||||||
|
background: url("/admin/img/logo.svg") no-repeat center left 15px;
|
||||||
|
background-size: 15px 23px;
|
||||||
|
padding: 0 15px;
|
||||||
|
text-indent: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="checkbox"][id$="Toggle"] { display: none; }
|
||||||
|
[type="checkbox"][id$="Toggle"]:checked ~ #bpAbout,
|
||||||
|
[type="checkbox"][id$="Toggle"]:checked ~ #bpMoreInfo {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pihole_card {
|
||||||
|
width: 400px;
|
||||||
|
height: auto;
|
||||||
|
max-width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pihole_card p, #pihole_card a {
|
||||||
|
font-size: 13pt;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pihole_logo_splash {
|
||||||
|
height: auto;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Click anywhere else on screen to hide #bpAbout */
|
||||||
|
#bpAboutToggle:checked {
|
||||||
|
display: block;
|
||||||
|
height: 300px; /* VH Fallback */
|
||||||
|
height: 100vh;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bpAbout {
|
||||||
|
background: #3c8dbc;
|
||||||
|
border-bottom-left-radius: 5px;
|
||||||
|
border: 1px solid #fff;
|
||||||
|
border-right-width: 0;
|
||||||
|
box-shadow: -1px 1px 1px rgba(0, 0, 0, 0.12);
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: none;
|
||||||
|
font-size: 1.7rem;
|
||||||
|
top: 50px;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
width: 280px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aboutPH {
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
display: block;
|
||||||
|
padding: 10px;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aboutImg {
|
||||||
|
background: url("/admin/img/logo.svg") no-repeat center;
|
||||||
|
background-size: 90px 90px;
|
||||||
|
height: 90px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2px;
|
||||||
|
width: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aboutPH p { margin: 10px 0; }
|
||||||
|
.aboutPH small { display: block; font-size: 1.2rem; }
|
||||||
|
|
||||||
|
.aboutLink {
|
||||||
|
background: #fff;
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
display: table;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aboutLink a {
|
||||||
|
display: table-cell;
|
||||||
|
padding: 14px;
|
||||||
|
min-width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
background: #ecf0f5;
|
||||||
|
font-size: 1.65rem;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bpOutput {
|
||||||
|
background: #00c0ef;
|
||||||
|
border-radius: 3px;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
margin-top: 5px;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bpOutput::before {
|
||||||
|
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='7' height='14' viewBox='0 0 7 14'%3E%3Cpath fill='%23fff' d='M6 11a1.371 1.371 0 011 1v1a1.371 1.371 0 01-1 1H1a1.371 1.371 0 01-1-1v-1a1.371 1.371 0 011-1h1V8H1a1.371 1.371 0 01-1-1V6a1.371 1.371 0 011-1h3a1.371 1.371 0 011 1v5h1zM3.5 0A1.5 1.5 0 112 1.5 1.5 1.5 0 013.5 0z'/%3E%3C/svg%3E") no-repeat center left;
|
||||||
|
display: block;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
text-indent: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bpOutput.hidden { display: none; }
|
||||||
|
#bpOutput.success { background: #00a65a; }
|
||||||
|
#bpOutput.error { background: #dd4b39; }
|
||||||
|
|
||||||
|
.blockMsg, .flagMsg {
|
||||||
|
font: 700 1.8rem Consolas, Courier, monospace;
|
||||||
|
padding: 5px 10px 10px;
|
||||||
|
text-indent: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bpHelpTxt { padding-bottom: 10px; }
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
border-spacing: 5px 0;
|
||||||
|
display: table;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons * {
|
||||||
|
-moz-appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
border-radius: 3px;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
|
box-sizing: content-box;
|
||||||
|
display: table-cell;
|
||||||
|
font-size: 1.65rem;
|
||||||
|
margin-right: 5px;
|
||||||
|
min-height: 20px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: top;
|
||||||
|
white-space: nowrap;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons a:hover { text-decoration: none; }
|
||||||
|
|
||||||
|
/* Button hover dark overlay */
|
||||||
|
.buttons *:not(input):not([disabled]):hover {
|
||||||
|
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1));
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Button active shadow inset */
|
||||||
|
.buttons *:not([disabled]):not(input):active {
|
||||||
|
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Input border color */
|
||||||
|
.buttons *:not([disabled]):hover, .buttons input:focus {
|
||||||
|
border-color: rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
#bpButtons * { width: 50%; color: #fff; }
|
||||||
|
#bpBack { background-color: #00a65a; }
|
||||||
|
#bpInfo { background-color: #3c8dbc; }
|
||||||
|
#bpWhitelist { background-color: #dd4b39; }
|
||||||
|
|
||||||
|
#blockpage .buttons [type="password"][disabled] { color: rgba(0, 0, 0, 1); }
|
||||||
|
#blockpage .buttons [disabled] { color: rgba(0, 0, 0, 0.55); background-color: #e3e3e3; }
|
||||||
|
#blockpage .buttons [type="password"]:-ms-input-placeholder { color: rgba(51, 51, 51, 0.8); }
|
||||||
|
|
||||||
|
input[type="password"] { font-size: 1.5rem; }
|
||||||
|
|
||||||
|
@-webkit-keyframes slidein { from { max-height: 0; opacity: 0; } to { max-height: 300px; opacity: 1; } }
|
||||||
|
|
||||||
|
@keyframes slidein { from { max-height: 0; opacity: 0; } to { max-height: 300px; opacity: 1; } }
|
||||||
|
#bpMoreToggle:checked ~ #bpMoreInfo { display: block; margin-top: 8px; -webkit-animation: slidein 0.05s linear; animation: slidein 0.05s linear; }
|
||||||
|
#bpMoreInfo { display: none; margin-top: 10px; }
|
||||||
|
|
||||||
|
#bpQueryOutput {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
line-height: 1.65rem;
|
||||||
|
margin: 5px 0 0;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0 5px;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bpQueryOutput span { margin-right: 4px; }
|
||||||
|
|
||||||
|
#bpWLButtons { width: auto; margin-top: 10px; }
|
||||||
|
#bpWLButtons * { display: inline-block; }
|
||||||
|
#bpWLDomain { display: none; }
|
||||||
|
#bpWLPassword { width: 160px; }
|
||||||
|
#bpWhitelist { color: #fff; }
|
||||||
|
|
||||||
|
footer {
|
||||||
|
background: #fff;
|
||||||
|
border-top: 1px solid #d2d6de;
|
||||||
|
color: #444;
|
||||||
|
font: 1.2rem Consolas, Courier, monospace;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive Content */
|
||||||
|
@media only screen and (max-width: 500px) {
|
||||||
|
h1 a {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
min-width: 170px;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer span::before {
|
||||||
|
content: "Generated ";
|
||||||
|
}
|
||||||
|
|
||||||
|
footer span {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (min-width: 1251px) {
|
||||||
|
#bpWrapper, footer {
|
||||||
|
border-radius: 0 0 5px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bpAbout {
|
||||||
|
border-right-width: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 400px) {
|
||||||
|
#pihole_card {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pihole_card p, #pihole_card a {
|
||||||
|
font-size: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 256px) {
|
||||||
|
#pihole_logo_splash {
|
||||||
|
width: 90% !important;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
1
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 favor 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 algorithm.
|
||||||
|
#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 overridden 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 obligatory.
|
||||||
|
#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 recognize 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 recognized
|
||||||
|
#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,4 +0,0 @@
|
|||||||
<html>
|
|
||||||
<body>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
395
advanced/index.php
Normal file
395
advanced/index.php
Normal file
@@ -0,0 +1,395 @@
|
|||||||
|
<?php
|
||||||
|
/* Pi-hole: A black hole for Internet advertisements
|
||||||
|
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||||
|
* Network-wide ad blocking via your own hardware.
|
||||||
|
*
|
||||||
|
* This file is copyright under the latest version of the EUPL.
|
||||||
|
* Please see LICENSE file for your rights under this license. */
|
||||||
|
|
||||||
|
// Sanitize SERVER_NAME output
|
||||||
|
$serverName = htmlspecialchars($_SERVER["SERVER_NAME"]);
|
||||||
|
// Remove external ipv6 brackets if any
|
||||||
|
$serverName = preg_replace('/^\[(.*)\]$/', '${1}', $serverName);
|
||||||
|
|
||||||
|
if (!is_file("/etc/pihole/setupVars.conf"))
|
||||||
|
die("[ERROR] File not found: <code>/etc/pihole/setupVars.conf</code>");
|
||||||
|
|
||||||
|
// Get values from setupVars.conf
|
||||||
|
$setupVars = parse_ini_file("/etc/pihole/setupVars.conf");
|
||||||
|
$svPasswd = !empty($setupVars["WEBPASSWORD"]);
|
||||||
|
$svEmail = (!empty($setupVars["ADMIN_EMAIL"]) && filter_var($setupVars["ADMIN_EMAIL"], FILTER_VALIDATE_EMAIL)) ? $setupVars["ADMIN_EMAIL"] : "";
|
||||||
|
unset($setupVars);
|
||||||
|
|
||||||
|
// Set landing page location, found within /var/www/html/
|
||||||
|
$landPage = "../landing.php";
|
||||||
|
|
||||||
|
// Define array for hostnames to be accepted as self address for splash page
|
||||||
|
$authorizedHosts = [ "localhost" ];
|
||||||
|
if (!empty($_SERVER["FQDN"])) {
|
||||||
|
// If setenv.add-environment = ("fqdn" => "true") is configured in lighttpd,
|
||||||
|
// append $serverName to $authorizedHosts
|
||||||
|
array_push($authorizedHosts, $serverName);
|
||||||
|
} else if (!empty($_SERVER["VIRTUAL_HOST"])) {
|
||||||
|
// Append virtual hostname to $authorizedHosts
|
||||||
|
array_push($authorizedHosts, $_SERVER["VIRTUAL_HOST"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set which extension types render as Block Page (Including "" for index.ext)
|
||||||
|
$validExtTypes = array("asp", "htm", "html", "php", "rss", "xml", "");
|
||||||
|
|
||||||
|
// Get extension of current URL
|
||||||
|
$currentUrlExt = pathinfo($_SERVER["REQUEST_URI"], PATHINFO_EXTENSION);
|
||||||
|
|
||||||
|
// Set mobile friendly viewport
|
||||||
|
$viewPort = '<meta name="viewport" content="width=device-width, initial-scale=1">';
|
||||||
|
|
||||||
|
// Set response header
|
||||||
|
function setHeader($type = "x") {
|
||||||
|
header("X-Pi-hole: A black hole for Internet advertisements.");
|
||||||
|
if (isset($type) && $type === "js") header("Content-Type: application/javascript");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine block page type
|
||||||
|
if ($serverName === "pi.hole"
|
||||||
|
|| (!empty($_SERVER["VIRTUAL_HOST"]) && $serverName === $_SERVER["VIRTUAL_HOST"])) {
|
||||||
|
// Redirect to Web Interface
|
||||||
|
exit(header("Location: /admin"));
|
||||||
|
} elseif (filter_var($serverName, FILTER_VALIDATE_IP) || in_array($serverName, $authorizedHosts)) {
|
||||||
|
// When directly browsing via IP or authorized hostname
|
||||||
|
// Render splash/landing page based off presence of $landPage file
|
||||||
|
// Unset variables so as to not be included in $landPage or $splashPage
|
||||||
|
unset($svPasswd, $svEmail, $authorizedHosts, $validExtTypes, $currentUrlExt);
|
||||||
|
// If $landPage file is present
|
||||||
|
if (is_file(getcwd()."/$landPage")) {
|
||||||
|
unset($serverName, $viewPort); // unset extra variables not to be included in $landpage
|
||||||
|
include $landPage;
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
// If $landPage file was not present, Set Splash Page output
|
||||||
|
$splashPage = <<<EOT
|
||||||
|
<!doctype html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='utf-8'>
|
||||||
|
$viewPort
|
||||||
|
<title>● $serverName</title>
|
||||||
|
<link rel='stylesheet' href='/pihole/blockingpage.css'>
|
||||||
|
<link rel='shortcut icon' href='/admin/img/favicons/favicon.ico' type='image/x-icon'>
|
||||||
|
</head>
|
||||||
|
<body id='splashpage'>
|
||||||
|
<div id="pihole_card">
|
||||||
|
<img src='/admin/img/logo.svg' alt='Pi-hole logo' id="pihole_logo_splash" />
|
||||||
|
<p>Pi-<strong>hole</strong>: Your black hole for Internet advertisements</p>
|
||||||
|
<a href='/admin'>Did you mean to go to the admin panel?</a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
EOT;
|
||||||
|
exit($splashPage);
|
||||||
|
} elseif ($currentUrlExt === "js") {
|
||||||
|
// Serve Pi-hole JavaScript for blocked domains requesting JS
|
||||||
|
exit(setHeader("js").'var x = "Pi-hole: A black hole for Internet advertisements."');
|
||||||
|
} elseif (strpos($_SERVER["REQUEST_URI"], "?") !== FALSE && isset($_SERVER["HTTP_REFERER"])) {
|
||||||
|
// Serve blank image upon receiving REQUEST_URI w/ query string & HTTP_REFERRER
|
||||||
|
// e.g: An iframe of a blocked domain
|
||||||
|
exit(setHeader().'<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"><script>window.close();</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=">
|
||||||
|
</body>
|
||||||
|
</html>');
|
||||||
|
} elseif (!in_array($currentUrlExt, $validExtTypes) || substr_count($_SERVER["REQUEST_URI"], "?")) {
|
||||||
|
// Serve SVG upon receiving non $validExtTypes URL extension or query string
|
||||||
|
// e.g: Not an iframe of a blocked domain, such as when browsing to a file/query directly
|
||||||
|
// QoL addition: Allow the SVG to be clicked on in order to quickly show the full Block Page
|
||||||
|
$blockImg = '<a href="/">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="110" height="16">
|
||||||
|
<circle cx="8" cy="8" r="7" fill="none" stroke="rgba(152,2,2,.5)" stroke-width="2"/>
|
||||||
|
<path fill="rgba(152,2,2,.5)" d="M11.526 3.04l1.414 1.415-8.485 8.485-1.414-1.414z"/>
|
||||||
|
<text x="19.3" y="12" opacity=".3" style="font:11px Arial">
|
||||||
|
Blocked by Pi-hole
|
||||||
|
</text>
|
||||||
|
</svg>
|
||||||
|
</a>';
|
||||||
|
exit(setHeader()."<!doctype html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='utf-8'>
|
||||||
|
$viewPort
|
||||||
|
</head>
|
||||||
|
<body>$blockImg</body>
|
||||||
|
</html>");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start processing Block Page from here */
|
||||||
|
|
||||||
|
// Define admin email address text based off $svEmail presence
|
||||||
|
$bpAskAdmin = !empty($svEmail) ? '<a href="mailto:'.$svEmail.'?subject=Site Blocked: '.$serverName.'"></a>' : "<span/>";
|
||||||
|
|
||||||
|
// Get possible non-standard location of FTL's database
|
||||||
|
$FTLsettings = parse_ini_file("/etc/pihole/pihole-FTL.conf");
|
||||||
|
if (isset($FTLsettings["GRAVITYDB"])) {
|
||||||
|
$gravityDBFile = $FTLsettings["GRAVITYDB"];
|
||||||
|
} else {
|
||||||
|
$gravityDBFile = "/etc/pihole/gravity.db";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to gravity.db
|
||||||
|
try {
|
||||||
|
$db = new SQLite3($gravityDBFile, SQLITE3_OPEN_READONLY);
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
die("[ERROR]: Failed to connect to gravity.db");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all adlist addresses
|
||||||
|
$adlistResults = $db->query("SELECT address FROM vw_adlist");
|
||||||
|
$adlistsUrls = array();
|
||||||
|
while ($row = $adlistResults->fetchArray()) {
|
||||||
|
array_push($adlistsUrls, $row[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($adlistsUrls))
|
||||||
|
die("[ERROR]: There are no adlists enabled");
|
||||||
|
|
||||||
|
// Get total number of blocklists (Including Whitelist, Blacklist & Wildcard lists)
|
||||||
|
$adlistsCount = count($adlistsUrls) + 3;
|
||||||
|
|
||||||
|
// Set query timeout
|
||||||
|
ini_set("default_socket_timeout", 3);
|
||||||
|
|
||||||
|
// Logic for querying blocklists
|
||||||
|
function queryAds($serverName) {
|
||||||
|
// Determine the time it takes while querying adlists
|
||||||
|
$preQueryTime = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"];
|
||||||
|
$queryAdsURL = sprintf(
|
||||||
|
"http://127.0.0.1:%s/admin/scripts/pi-hole/php/queryads.php?domain=%s&bp",
|
||||||
|
$_SERVER["SERVER_PORT"],
|
||||||
|
$serverName
|
||||||
|
);
|
||||||
|
$queryAds = file($queryAdsURL, FILE_IGNORE_NEW_LINES);
|
||||||
|
$queryAds = array_values(array_filter(preg_replace("/data:\s+/", "", $queryAds)));
|
||||||
|
$queryTime = sprintf("%.0f", (microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"]) - $preQueryTime);
|
||||||
|
|
||||||
|
// Exception Handling
|
||||||
|
try {
|
||||||
|
// Define Exceptions
|
||||||
|
if (strpos($queryAds[0], "No exact results") !== FALSE) {
|
||||||
|
// Return "none" into $queryAds array
|
||||||
|
return array("0" => "none");
|
||||||
|
} else if ($queryTime >= ini_get("default_socket_timeout")) {
|
||||||
|
// Connection Timeout
|
||||||
|
throw new Exception ("Connection timeout (".ini_get("default_socket_timeout")."s)");
|
||||||
|
} elseif (!strpos($queryAds[0], ".") !== false) {
|
||||||
|
// Unknown $queryAds output
|
||||||
|
throw new Exception ("Unhandled error message (<code>$queryAds[0]</code>)");
|
||||||
|
}
|
||||||
|
return $queryAds;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// Return exception as array
|
||||||
|
return array("0" => "error", "1" => $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get results of queryads.php exact search
|
||||||
|
$queryAds = queryAds($serverName);
|
||||||
|
|
||||||
|
// Pass error through to Block Page
|
||||||
|
if ($queryAds[0] === "error")
|
||||||
|
die("[ERROR]: Unable to parse results from <i>queryads.php</i>: <code>".$queryAds[1]."</code>");
|
||||||
|
|
||||||
|
// Count total number of matching blocklists
|
||||||
|
$featuredTotal = count($queryAds);
|
||||||
|
|
||||||
|
// Place results into key => value array
|
||||||
|
$queryResults = null;
|
||||||
|
foreach ($queryAds as $str) {
|
||||||
|
$value = explode(" ", $str);
|
||||||
|
@$queryResults[$value[0]] .= "$value[1]";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if domain has been blacklisted, whitelisted, wildcarded or CNAME blocked
|
||||||
|
if (strpos($queryAds[0], "blacklist") !== FALSE) {
|
||||||
|
$notableFlagClass = "blacklist";
|
||||||
|
$adlistsUrls = array("π" => substr($queryAds[0], 2));
|
||||||
|
} elseif (strpos($queryAds[0], "whitelist") !== FALSE) {
|
||||||
|
$notableFlagClass = "noblock";
|
||||||
|
$adlistsUrls = array("π" => substr($queryAds[0], 2));
|
||||||
|
$wlInfo = "recentwl";
|
||||||
|
} elseif (strpos($queryAds[0], "wildcard") !== FALSE) {
|
||||||
|
$notableFlagClass = "wildcard";
|
||||||
|
$adlistsUrls = array("π" => substr($queryAds[0], 2));
|
||||||
|
} elseif ($queryAds[0] === "none") {
|
||||||
|
$featuredTotal = "0";
|
||||||
|
$notableFlagClass = "noblock";
|
||||||
|
|
||||||
|
// QoL addition: Determine appropriate info message if CNAME exists
|
||||||
|
// Suggests to the user that $serverName has a CNAME (alias) that may be blocked
|
||||||
|
$dnsRecord = dns_get_record("$serverName")[0];
|
||||||
|
if (array_key_exists("target", $dnsRecord)) {
|
||||||
|
$wlInfo = $dnsRecord['target'];
|
||||||
|
} else {
|
||||||
|
$wlInfo = "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set #bpOutput notification
|
||||||
|
$wlOutputClass = (isset($wlInfo) && $wlInfo === "recentwl") ? $wlInfo : "hidden";
|
||||||
|
$wlOutput = (isset($wlInfo) && $wlInfo !== "recentwl") ? "<a href='http://$wlInfo'>$wlInfo</a>" : "";
|
||||||
|
|
||||||
|
// Get Pi-hole Core version
|
||||||
|
$phVersion = exec("cd /etc/.pihole/ && git describe --long --tags");
|
||||||
|
|
||||||
|
// Print $execTime on development branches
|
||||||
|
// Testing for - is marginally faster than "git rev-parse --abbrev-ref HEAD"
|
||||||
|
if (explode("-", $phVersion)[1] != "0")
|
||||||
|
$execTime = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"];
|
||||||
|
|
||||||
|
// Please Note: Text is added via CSS to allow an admin to provide a localized
|
||||||
|
// language without the need to edit this file
|
||||||
|
|
||||||
|
setHeader();
|
||||||
|
?>
|
||||||
|
<!doctype html>
|
||||||
|
<!-- Pi-hole: A black hole for Internet advertisements
|
||||||
|
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||||
|
* Network-wide ad blocking via your own hardware.
|
||||||
|
*
|
||||||
|
* This file is copyright under the latest version of the EUPL. -->
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<?=$viewPort ?>
|
||||||
|
<meta name="robots" content="noindex,nofollow">
|
||||||
|
<meta http-equiv="x-dns-prefetch-control" content="off">
|
||||||
|
<link rel="stylesheet" href="pihole/blockingpage.css">
|
||||||
|
<link rel="shortcut icon" href="admin/img/favicons/favicon.ico" type="image/x-icon">
|
||||||
|
<title>● <?=$serverName ?></title>
|
||||||
|
<script src="admin/scripts/vendor/jquery.min.js"></script>
|
||||||
|
<script>
|
||||||
|
window.onload = function () {
|
||||||
|
<?php
|
||||||
|
// Remove href fallback from "Back to safety" button
|
||||||
|
if ($featuredTotal > 0) {
|
||||||
|
echo '$("#bpBack").removeAttr("href");';
|
||||||
|
|
||||||
|
// Enable whitelisting if JS is available
|
||||||
|
echo '$("#bpWhitelist").prop("disabled", false);';
|
||||||
|
|
||||||
|
// Enable password input if necessary
|
||||||
|
if (!empty($svPasswd)) {
|
||||||
|
echo '$("#bpWLPassword").attr("placeholder", "Password");';
|
||||||
|
echo '$("#bpWLPassword").prop("disabled", false);';
|
||||||
|
}
|
||||||
|
// Otherwise hide the input
|
||||||
|
else {
|
||||||
|
echo '$("#bpWLPassword").hide();';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body id="blockpage"><div id="bpWrapper">
|
||||||
|
<header>
|
||||||
|
<h1 id="bpTitle">
|
||||||
|
<a class="title" href="/"><?php //Website Blocked ?></a>
|
||||||
|
</h1>
|
||||||
|
<div class="spc"></div>
|
||||||
|
|
||||||
|
<input id="bpAboutToggle" type="checkbox">
|
||||||
|
<div id="bpAbout">
|
||||||
|
<div class="aboutPH">
|
||||||
|
<div class="aboutImg"></div>
|
||||||
|
<p>Open Source Ad Blocker
|
||||||
|
<small>Designed for Raspberry Pi</small>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="aboutLink">
|
||||||
|
<a class="linkPH" href="https://docs.pi-hole.net/"><?php //About PH ?></a>
|
||||||
|
<?php if (!empty($svEmail)) echo '<a class="linkEmail" href="mailto:'.$svEmail.'"></a>'; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="bpAlt">
|
||||||
|
<label class="altBtn" for="bpAboutToggle"><?php //Why am I here? ?></label>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<div id="bpOutput" class="<?=$wlOutputClass ?>"><?=$wlOutput ?></div>
|
||||||
|
<div id="bpBlock">
|
||||||
|
<p class="blockMsg"><?=$serverName ?></p>
|
||||||
|
</div>
|
||||||
|
<?php if(isset($notableFlagClass)) { ?>
|
||||||
|
<div id="bpFlag">
|
||||||
|
<p class="flagMsg <?=$notableFlagClass ?>"></p>
|
||||||
|
</div>
|
||||||
|
<?php } ?>
|
||||||
|
<div id="bpHelpTxt"><?=$bpAskAdmin ?></div>
|
||||||
|
<div id="bpButtons" class="buttons">
|
||||||
|
<a id="bpBack" onclick="javascript:history.back()" href="about:home"></a>
|
||||||
|
<?php if ($featuredTotal > 0) echo '<label id="bpInfo" for="bpMoreToggle"></label>'; ?>
|
||||||
|
</div>
|
||||||
|
<input id="bpMoreToggle" type="checkbox">
|
||||||
|
<div id="bpMoreInfo">
|
||||||
|
<span id="bpFoundIn"><span><?=$featuredTotal ?></span><?=$adlistsCount ?></span>
|
||||||
|
<pre id='bpQueryOutput'><?php if ($featuredTotal > 0) foreach ($queryResults as $num => $value) { echo "<span>[$num]:</span>$adlistsUrls[$num]\n"; } ?></pre>
|
||||||
|
|
||||||
|
<form id="bpWLButtons" class="buttons">
|
||||||
|
<input id="bpWLDomain" type="text" value="<?=$serverName ?>" disabled>
|
||||||
|
<input id="bpWLPassword" type="password" placeholder="JavaScript disabled" disabled>
|
||||||
|
<button id="bpWhitelist" type="button" disabled></button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer><span><?=date("l g:i A, F dS"); ?>.</span> Pi-hole <?=$phVersion ?> (<?=gethostname()."/".$_SERVER["SERVER_ADDR"]; if (isset($execTime)) printf("/%.2fs", $execTime); ?>)</footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function add() {
|
||||||
|
$("#bpOutput").removeClass("hidden error exception");
|
||||||
|
$("#bpOutput").addClass("add");
|
||||||
|
var domain = "<?=$serverName ?>";
|
||||||
|
var pw = $("#bpWLPassword");
|
||||||
|
if(domain.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.ajax({
|
||||||
|
url: "/admin/scripts/pi-hole/php/add.php",
|
||||||
|
method: "post",
|
||||||
|
data: {"domain":domain, "list":"white", "pw":pw.val()},
|
||||||
|
success: function(response) {
|
||||||
|
if(response.indexOf("Pi-hole blocking") !== -1) {
|
||||||
|
setTimeout(function(){window.location.reload(1);}, 10000);
|
||||||
|
$("#bpOutput").removeClass("add");
|
||||||
|
$("#bpOutput").addClass("success");
|
||||||
|
$("#bpOutput").html("");
|
||||||
|
} else {
|
||||||
|
$("#bpOutput").removeClass("add");
|
||||||
|
$("#bpOutput").addClass("error");
|
||||||
|
$("#bpOutput").html(""+response+"");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(jqXHR, exception) {
|
||||||
|
$("#bpOutput").removeClass("add");
|
||||||
|
$("#bpOutput").addClass("exception");
|
||||||
|
$("#bpOutput").html("");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
<?php if ($featuredTotal > 0) { ?>
|
||||||
|
$(document).keypress(function(e) {
|
||||||
|
if(e.which === 13 && $("#bpWLPassword").is(":focus")) {
|
||||||
|
add();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$("#bpWhitelist").on("click", function() {
|
||||||
|
add();
|
||||||
|
});
|
||||||
|
<?php } ?>
|
||||||
|
</script>
|
||||||
|
</body></html>
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
server.modules = (
|
|
||||||
"mod_expire",
|
|
||||||
"mod_compress",
|
|
||||||
"mod_redirect",
|
|
||||||
"mod_rewrite"
|
|
||||||
)
|
|
||||||
|
|
||||||
server.document-root = "/var/www"
|
|
||||||
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"
|
|
||||||
|
|
||||||
# Set access to 1 day for better query performance when the list gets so large
|
|
||||||
# http://jacobsalmela.com/raspberry-pi-block-ads-adtrap/#comment-2013820434
|
|
||||||
$HTTP["url"] =~ "^/pihole/" {
|
|
||||||
expire.url = ("" => "access plus 1 days")
|
|
||||||
}
|
|
||||||
|
|
||||||
# Rewrites all URLs to the /var/www/pihole/index.html
|
|
||||||
$HTTP["host"] =~ ".*" {
|
|
||||||
url.rewrite = (".*" => "pihole/index.html")
|
|
||||||
}
|
|
||||||
96
advanced/lighttpd.conf.debian
Normal file
96
advanced/lighttpd.conf.debian
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
# 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 SEPARATE CONFIG FILE: #
|
||||||
|
# /etc/lighttpd/external.conf #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
server.modules = (
|
||||||
|
"mod_access",
|
||||||
|
"mod_accesslog",
|
||||||
|
"mod_auth",
|
||||||
|
"mod_expire",
|
||||||
|
"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 = "/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", ".md", ".yml", ".ini" )
|
||||||
|
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
|
||||||
|
|
||||||
|
mimetype.assign = (
|
||||||
|
".ico" => "image/x-icon",
|
||||||
|
".jpeg" => "image/jpeg",
|
||||||
|
".jpg" => "image/jpeg",
|
||||||
|
".png" => "image/png",
|
||||||
|
".svg" => "image/svg+xml",
|
||||||
|
".css" => "text/css; charset=utf-8",
|
||||||
|
".html" => "text/html; charset=utf-8",
|
||||||
|
".js" => "text/javascript; charset=utf-8",
|
||||||
|
".json" => "application/json; charset=utf-8",
|
||||||
|
".map" => "application/json; charset=utf-8",
|
||||||
|
".txt" => "text/plain; charset=utf-8",
|
||||||
|
".eot" => "application/vnd.ms-fontobject",
|
||||||
|
".otf" => "font/otf",
|
||||||
|
".ttc" => "font/collection",
|
||||||
|
".ttf" => "font/ttf",
|
||||||
|
".woff" => "font/woff",
|
||||||
|
".woff2" => "font/woff2"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add user chosen options held in external file
|
||||||
|
# This uses include_shell instead of an include wildcard for compatibility
|
||||||
|
include_shell "cat external.conf 2>/dev/null"
|
||||||
|
|
||||||
|
# default listening port for IPv6 falls back to the IPv4 port
|
||||||
|
include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port
|
||||||
|
|
||||||
|
# Prevent Lighttpd from enabling Let's Encrypt SSL for every blocked domain
|
||||||
|
#include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
|
||||||
|
include_shell "find /etc/lighttpd/conf-enabled -name '*.conf' -a ! -name 'letsencrypt.conf' -printf 'include \"%p\"\n' 2>/dev/null"
|
||||||
|
|
||||||
|
# If the URL starts with /admin, it is the Web interface
|
||||||
|
$HTTP["url"] =~ "^/admin/" {
|
||||||
|
# Create a response header for debugging using curl -I
|
||||||
|
setenv.add-response-header = (
|
||||||
|
"X-Pi-hole" => "The Pi-hole Web interface is working!",
|
||||||
|
"X-Frame-Options" => "DENY"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Block . files from being served, such as .git, .github, .gitignore
|
||||||
|
$HTTP["url"] =~ "^/admin/\.(.*)" {
|
||||||
|
url.access-deny = ("")
|
||||||
|
}
|
||||||
|
|
||||||
|
# allow teleporter and API qr code iframe on settings page
|
||||||
|
$HTTP["url"] =~ "/(teleporter|api_token)\.php$" {
|
||||||
|
$HTTP["referer"] =~ "/admin/settings\.php" {
|
||||||
|
setenv.add-response-header = ( "X-Frame-Options" => "SAMEORIGIN" )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Default expire header
|
||||||
|
expire.url = ( "" => "access plus 0 seconds" )
|
||||||
104
advanced/lighttpd.conf.fedora
Normal file
104
advanced/lighttpd.conf.fedora
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
# 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 SEPARATE CONFIG FILE: #
|
||||||
|
# /etc/lighttpd/external.conf #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
server.modules = (
|
||||||
|
"mod_access",
|
||||||
|
"mod_auth",
|
||||||
|
"mod_expire",
|
||||||
|
"mod_fastcgi",
|
||||||
|
"mod_accesslog",
|
||||||
|
"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 = "/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", ".md", ".yml", ".ini" )
|
||||||
|
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
|
||||||
|
|
||||||
|
mimetype.assign = (
|
||||||
|
".ico" => "image/x-icon",
|
||||||
|
".jpeg" => "image/jpeg",
|
||||||
|
".jpg" => "image/jpeg",
|
||||||
|
".png" => "image/png",
|
||||||
|
".svg" => "image/svg+xml",
|
||||||
|
".css" => "text/css; charset=utf-8",
|
||||||
|
".html" => "text/html; charset=utf-8",
|
||||||
|
".js" => "text/javascript; charset=utf-8",
|
||||||
|
".json" => "application/json; charset=utf-8",
|
||||||
|
".map" => "application/json; charset=utf-8",
|
||||||
|
".txt" => "text/plain; charset=utf-8",
|
||||||
|
".eot" => "application/vnd.ms-fontobject",
|
||||||
|
".otf" => "font/otf",
|
||||||
|
".ttc" => "font/collection",
|
||||||
|
".ttf" => "font/ttf",
|
||||||
|
".woff" => "font/woff",
|
||||||
|
".woff2" => "font/woff2"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add user chosen options held in external file
|
||||||
|
# This uses include_shell instead of an include wildcard for compatibility
|
||||||
|
include_shell "cat external.conf 2>/dev/null"
|
||||||
|
|
||||||
|
# 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!",
|
||||||
|
"X-Frame-Options" => "DENY"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Block . files from being served, such as .git, .github, .gitignore
|
||||||
|
$HTTP["url"] =~ "^/admin/\.(.*)" {
|
||||||
|
url.access-deny = ("")
|
||||||
|
}
|
||||||
|
|
||||||
|
# allow teleporter and API qr code iframe on settings page
|
||||||
|
$HTTP["url"] =~ "/(teleporter|api_token)\.php$" {
|
||||||
|
$HTTP["referer"] =~ "/admin/settings\.php" {
|
||||||
|
setenv.add-response-header = ( "X-Frame-Options" => "SAMEORIGIN" )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Default expire header
|
||||||
|
expire.url = ( "" => "access plus 0 seconds" )
|
||||||
File diff suppressed because it is too large
Load Diff
224
automated install/uninstall.sh
Executable file
224
automated install/uninstall.sh
Executable file
@@ -0,0 +1,224 @@
|
|||||||
|
#!/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.
|
||||||
|
|
||||||
|
source "/opt/pihole/COL_TABLE"
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
read -rp " ${QST} Are you sure you would like to remove ${COL_WHITE}Pi-hole${COL_NC}? [y/N] " yn
|
||||||
|
case ${yn} in
|
||||||
|
[Yy]* ) break;;
|
||||||
|
[Nn]* ) echo -e "${OVER} ${COL_LIGHT_GREEN}Uninstall has been canceled${COL_NC}"; exit 0;;
|
||||||
|
* ) echo -e "${OVER} ${COL_LIGHT_GREEN}Uninstall has been canceled${COL_NC}"; exit 0;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Must be root to uninstall
|
||||||
|
str="Root user check"
|
||||||
|
if [[ ${EUID} -eq 0 ]]; then
|
||||||
|
echo -e " ${TICK} ${str}"
|
||||||
|
else
|
||||||
|
# Check if sudo is actually installed
|
||||||
|
# If it isn't, exit because the uninstall can not complete
|
||||||
|
if [ -x "$(command -v sudo)" ]; then
|
||||||
|
export SUDO="sudo"
|
||||||
|
else
|
||||||
|
echo -e " ${CROSS} ${str}
|
||||||
|
Script called with non-root privileges
|
||||||
|
The Pi-hole requires elevated privileges to uninstall"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
|
||||||
|
PH_TEST="true"
|
||||||
|
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
|
||||||
|
# setupVars set in basic-install.sh
|
||||||
|
source "${setupVars}"
|
||||||
|
|
||||||
|
# package_manager_detect() sourced from basic-install.sh
|
||||||
|
package_manager_detect
|
||||||
|
|
||||||
|
# Install packages used by the Pi-hole
|
||||||
|
DEPS=("${INSTALLER_DEPS[@]}" "${PIHOLE_DEPS[@]}")
|
||||||
|
if [[ "${INSTALL_WEB_SERVER}" == true ]]; then
|
||||||
|
# Install the Web dependencies
|
||||||
|
DEPS+=("${PIHOLE_WEB_DEPS[@]}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Compatibility
|
||||||
|
if [ -x "$(command -v apt-get)" ]; then
|
||||||
|
# Debian Family
|
||||||
|
PKG_REMOVE=("${PKG_MANAGER}" -y remove --purge)
|
||||||
|
package_check() {
|
||||||
|
dpkg-query -W -f='${Status}' "$1" 2>/dev/null | grep -c "ok installed"
|
||||||
|
}
|
||||||
|
elif [ -x "$(command -v rpm)" ]; then
|
||||||
|
# Fedora Family
|
||||||
|
PKG_REMOVE=("${PKG_MANAGER}" remove -y)
|
||||||
|
package_check() {
|
||||||
|
rpm -qa | grep "^$1-" > /dev/null
|
||||||
|
}
|
||||||
|
else
|
||||||
|
echo -e " ${CROSS} OS distribution not supported"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
removeAndPurge() {
|
||||||
|
# Purge dependencies
|
||||||
|
echo ""
|
||||||
|
for i in "${DEPS[@]}"; do
|
||||||
|
if package_check "${i}" > /dev/null; then
|
||||||
|
while true; do
|
||||||
|
read -rp " ${QST} Do you wish to remove ${COL_WHITE}${i}${COL_NC} from your system? [Y/N] " yn
|
||||||
|
case ${yn} in
|
||||||
|
[Yy]* )
|
||||||
|
echo -ne " ${INFO} Removing ${i}...";
|
||||||
|
${SUDO} "${PKG_REMOVE[@]}" "${i}" &> /dev/null;
|
||||||
|
echo -e "${OVER} ${INFO} Removed ${i}";
|
||||||
|
break;;
|
||||||
|
[Nn]* ) echo -e " ${INFO} Skipped ${i}"; break;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo -e " ${INFO} Package ${i} not installed"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Remove dnsmasq config files
|
||||||
|
${SUDO} rm -f /etc/dnsmasq.conf /etc/dnsmasq.conf.orig /etc/dnsmasq.d/*-pihole*.conf &> /dev/null
|
||||||
|
echo -e " ${TICK} Removing dnsmasq config files"
|
||||||
|
|
||||||
|
# Call removeNoPurge to remove Pi-hole specific files
|
||||||
|
removeNoPurge
|
||||||
|
}
|
||||||
|
|
||||||
|
removeNoPurge() {
|
||||||
|
# Only web directories/files that are created by Pi-hole should be removed
|
||||||
|
echo -ne " ${INFO} Removing Web Interface..."
|
||||||
|
${SUDO} rm -rf /var/www/html/admin &> /dev/null
|
||||||
|
${SUDO} rm -rf /var/www/html/pihole &> /dev/null
|
||||||
|
${SUDO} rm -f /var/www/html/index.lighttpd.orig &> /dev/null
|
||||||
|
|
||||||
|
# If the web directory is empty after removing these files, then the parent html directory 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
|
||||||
|
echo -e "${OVER} ${TICK} Removed Web Interface"
|
||||||
|
|
||||||
|
# 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
|
||||||
|
${SUDO} mv /etc/crontab /etc/crontab.pihole
|
||||||
|
${SUDO} mv /etc/crontab.orig /etc/crontab
|
||||||
|
${SUDO} service cron restart
|
||||||
|
echo -e " ${TICK} Restored the default system cron"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Attempt to preserve backwards compatibility with older versions
|
||||||
|
if [[ -f /etc/cron.d/pihole ]];then
|
||||||
|
${SUDO} rm -f /etc/cron.d/pihole &> /dev/null
|
||||||
|
echo -e " ${TICK} Removed /etc/cron.d/pihole"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if package_check lighttpd > /dev/null; then
|
||||||
|
if [[ -f /etc/lighttpd/lighttpd.conf.orig ]]; then
|
||||||
|
${SUDO} mv /etc/lighttpd/lighttpd.conf.orig /etc/lighttpd/lighttpd.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -f /etc/lighttpd/external.conf ]]; then
|
||||||
|
${SUDO} rm /etc/lighttpd/external.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e " ${TICK} Removed lighttpd configs"
|
||||||
|
fi
|
||||||
|
|
||||||
|
${SUDO} rm -f /etc/dnsmasq.d/adList.conf &> /dev/null
|
||||||
|
${SUDO} rm -f /etc/dnsmasq.d/01-pihole.conf &> /dev/null
|
||||||
|
${SUDO} rm -f /etc/dnsmasq.d/06-rfc6761.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 -f /usr/local/bin/pihole &> /dev/null
|
||||||
|
${SUDO} rm -f /etc/bash_completion.d/pihole &> /dev/null
|
||||||
|
${SUDO} rm -f /etc/sudoers.d/pihole &> /dev/null
|
||||||
|
echo -e " ${TICK} Removed config files"
|
||||||
|
|
||||||
|
# Restore Resolved
|
||||||
|
if [[ -e /etc/systemd/resolved.conf.orig ]]; then
|
||||||
|
${SUDO} cp -p /etc/systemd/resolved.conf.orig /etc/systemd/resolved.conf
|
||||||
|
systemctl reload-or-restart systemd-resolved
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove FTL
|
||||||
|
if command -v pihole-FTL &> /dev/null; then
|
||||||
|
echo -ne " ${INFO} Removing pihole-FTL..."
|
||||||
|
if [[ -x "$(command -v systemctl)" ]]; then
|
||||||
|
systemctl stop pihole-FTL
|
||||||
|
else
|
||||||
|
service pihole-FTL stop
|
||||||
|
fi
|
||||||
|
${SUDO} rm -f /etc/init.d/pihole-FTL
|
||||||
|
${SUDO} rm -f /usr/bin/pihole-FTL
|
||||||
|
echo -e "${OVER} ${TICK} Removed pihole-FTL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If the pihole manpage exists, then delete and rebuild man-db
|
||||||
|
if [[ -f /usr/local/share/man/man8/pihole.8 ]]; then
|
||||||
|
${SUDO} rm -f /usr/local/share/man/man8/pihole.8 /usr/local/share/man/man8/pihole-FTL.8 /usr/local/share/man/man5/pihole-FTL.conf.5
|
||||||
|
${SUDO} mandb -q &>/dev/null
|
||||||
|
echo -e " ${TICK} Removed pihole man page"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If the pihole user exists, then remove
|
||||||
|
if id "pihole" &> /dev/null; then
|
||||||
|
if ${SUDO} userdel -r pihole 2> /dev/null; then
|
||||||
|
echo -e " ${TICK} Removed 'pihole' user"
|
||||||
|
else
|
||||||
|
echo -e " ${CROSS} Unable to remove 'pihole' user"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
# If the pihole group exists, then remove
|
||||||
|
if getent group "pihole" &> /dev/null; then
|
||||||
|
if ${SUDO} groupdel pihole 2> /dev/null; then
|
||||||
|
echo -e " ${TICK} Removed 'pihole' group"
|
||||||
|
else
|
||||||
|
echo -e " ${CROSS} Unable to remove 'pihole' group"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "\\n We're sorry to see you go, but thanks for checking out Pi-hole!
|
||||||
|
If you need help, reach out to us on GitHub, Discourse, Reddit or Twitter
|
||||||
|
Reinstall at any time: ${COL_WHITE}curl -sSL https://install.pi-hole.net | bash${COL_NC}
|
||||||
|
|
||||||
|
${COL_LIGHT_RED}Please reset the DNS on your router/clients to restore internet connectivity
|
||||||
|
${COL_LIGHT_GREEN}Uninstallation Complete! ${COL_NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
######### SCRIPT ###########
|
||||||
|
echo -e " ${INFO} Be sure to confirm if any dependencies should not be removed"
|
||||||
|
while true; do
|
||||||
|
echo -e " ${INFO} ${COL_YELLOW}The following dependencies may have been added by the Pi-hole install:"
|
||||||
|
echo -n " "
|
||||||
|
for i in "${DEPS[@]}"; do
|
||||||
|
echo -n "${i} "
|
||||||
|
done
|
||||||
|
echo "${COL_NC}"
|
||||||
|
read -rp " ${QST} Do you wish to go through each dependency for removal? (Choosing No will leave all dependencies installed) [Y/n] " yn
|
||||||
|
case ${yn} in
|
||||||
|
[Yy]* ) removeAndPurge; break;;
|
||||||
|
[Nn]* ) removeNoPurge; break;;
|
||||||
|
* ) removeAndPurge; break;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
server.modules = (
|
|
||||||
"mod_access",
|
|
||||||
"mod_alias",
|
|
||||||
"mod_compress",
|
|
||||||
"mod_redirect",
|
|
||||||
"mod_rewrite"
|
|
||||||
)
|
|
||||||
|
|
||||||
server.document-root = "/var/www"
|
|
||||||
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"
|
|
||||||
|
|
||||||
$HTTP["host"] =~ "ads.hulu.com|ads-v-darwin.hulu.com" {
|
|
||||||
url.redirect = ( ".*" => "http://192.168.1.101:8200/MediaItems/19.mov")
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
media_dir=V,/var/lib/minidlna/videos/
|
|
||||||
port=8200
|
|
||||||
friendly_name=pihole
|
|
||||||
serial=12345678
|
|
||||||
model_number=1
|
|
||||||
inotify=yes
|
|
||||||
1104
gravity.sh
1104
gravity.sh
File diff suppressed because it is too large
Load Diff
152
manpages/pihole-FTL.8
Normal file
152
manpages/pihole-FTL.8
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
.TH "Pihole-FTL" "8" "pihole-FTL" "Pi-hole" "November 2020"
|
||||||
|
.SH "NAME"
|
||||||
|
pihole-FTL - Pi-hole : The Faster-Than-Light (FTL) Engine
|
||||||
|
.br
|
||||||
|
.SH "SYNOPSIS"
|
||||||
|
\fBservice pihole-FTL \fR(\fBstart\fR|\fBstop\fR|\fBrestart\fR)
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole-FTL debug\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL test\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL -v|-vv\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL -t\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL -b\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL -f\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL -h\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL dnsmasq-test\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL regex-test str\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL regex-test str rgx\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL lua\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL luac\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL dhcp-discover\fR
|
||||||
|
.br
|
||||||
|
\fBpihole-FTL --\fR (\fBoptions\fR)
|
||||||
|
.br
|
||||||
|
|
||||||
|
.SH "DESCRIPTION"
|
||||||
|
Pi-hole : The Faster-Than-Light (FTL) Engine is a lightweight, purpose-built daemon used to provide statistics needed for the Pi-hole Web Interface, and its API can be easily integrated into your own projects. Although it is an optional component of the Pi-hole ecosystem, it will be installed by default to provide statistics. As the name implies, FTL does its work \fIvery\fR \fIquickly\fR!
|
||||||
|
.br
|
||||||
|
|
||||||
|
Usage
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBservice pihole-FTL start\fR
|
||||||
|
.br
|
||||||
|
Start the pihole-FTL daemon
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBservice pihole-FTL stop\fR
|
||||||
|
.br
|
||||||
|
Stop the pihole-FTL daemon
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBservice pihole-FTL restart\fR
|
||||||
|
.br
|
||||||
|
If the pihole-FTP daemon is running, stop and then start, otherwise start.
|
||||||
|
.br
|
||||||
|
|
||||||
|
Command line arguments
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBdebug\fR
|
||||||
|
.br
|
||||||
|
Don't go into daemon mode (stay in foreground) + more verbose logging
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBtest\fR
|
||||||
|
.br
|
||||||
|
Start FTL and process everything, but shut down immediately afterwards
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-v, version\fR
|
||||||
|
.br
|
||||||
|
Don't start FTL, show only version
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-vv\fR
|
||||||
|
.br
|
||||||
|
Don't start FTL, show verbose version information of embedded applications
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-t, tag\fR
|
||||||
|
.br
|
||||||
|
Don't start FTL, show only git tag
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-b, branch\fR
|
||||||
|
.br
|
||||||
|
Don't start FTL, show only git branch FTL was compiled from
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-f, no-daemon\fR
|
||||||
|
.br
|
||||||
|
Don't go into background (daemon mode)
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-h, help\fR
|
||||||
|
.br
|
||||||
|
Don't start FTL, show help
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBdnsmasq-test\fR
|
||||||
|
.br
|
||||||
|
Test resolver config file syntax
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBregex-test str\fR
|
||||||
|
.br
|
||||||
|
Test str against all regular expressions in the database
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBregex-test str rgx\fR
|
||||||
|
.br
|
||||||
|
Test str against regular expression given by rgx
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBlua\fR
|
||||||
|
.br
|
||||||
|
Start the embedded Lua interpreter
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBluac\fR
|
||||||
|
.br
|
||||||
|
Execute the embedded Lua compiler
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBdhcp-discover\fR
|
||||||
|
.br
|
||||||
|
Discover DHCP servers in the local network
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB--\fR (options)
|
||||||
|
.br
|
||||||
|
Pass options to internal dnsmasq resolver
|
||||||
|
.br
|
||||||
|
.SH "EXAMPLE"
|
||||||
|
Command line arguments can be arbitrarily combined, e.g:
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole-FTL debug test\fR
|
||||||
|
.br
|
||||||
|
|
||||||
|
Start ftl in foreground with more verbose logging, process everything and shutdown immediately
|
||||||
|
.br
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
\fBpihole\fR(8), \fBpihole-FTL.conf\fR(5)
|
||||||
|
.br
|
||||||
|
.SH "COLOPHON"
|
||||||
|
|
||||||
|
Get sucked into the latest news and community activity by entering Pi-hole's orbit. Information about Pi-hole, and the latest version of the software can be found at https://pi-hole.net
|
||||||
|
.br
|
||||||
313
manpages/pihole-FTL.conf.5
Normal file
313
manpages/pihole-FTL.conf.5
Normal file
@@ -0,0 +1,313 @@
|
|||||||
|
.TH "pihole-FTL.conf" "5" "pihole-FTL.conf" "pihole-FTL.conf" "November 2020"
|
||||||
|
.SH "NAME"
|
||||||
|
|
||||||
|
pihole-FTL.conf - FTL's config file
|
||||||
|
.br
|
||||||
|
.SH "DESCRIPTION"
|
||||||
|
|
||||||
|
/etc/pihole/pihole-FTL.conf will be read by \fBpihole-FTL(8)\fR on startup.
|
||||||
|
.br
|
||||||
|
For each setting the option shown first is the default.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBBLOCKINGMODE=IP|IP-AAAA-NODATA|NODATA|NXDOMAIN|NULL\fR
|
||||||
|
.br
|
||||||
|
How should FTL reply to blocked queries?
|
||||||
|
|
||||||
|
IP - Pi-hole's IPs for blocked domains
|
||||||
|
|
||||||
|
IP-AAAA-NODATA - Pi-hole's IP + NODATA-IPv6 for blocked domains
|
||||||
|
|
||||||
|
NODATA - Using NODATA for blocked domains
|
||||||
|
|
||||||
|
NXDOMAIN - NXDOMAIN for blocked domains
|
||||||
|
|
||||||
|
NULL - Null IPs for blocked domains
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBCNAME_DEEP_INSPECT=true|false\fR
|
||||||
|
.br
|
||||||
|
Use this option to disable deep CNAME inspection. This might be beneficial for very low-end devices.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBBLOCK_ESNI=true|false\fR
|
||||||
|
.br
|
||||||
|
Block requests to _esni.* sub-domains.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBMAXLOGAGE=24.0\fR
|
||||||
|
.br
|
||||||
|
Up to how many hours of queries should be imported from the database and logs?
|
||||||
|
.br
|
||||||
|
Maximum is 744 (31 days)
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBPRIVACYLEVEL=0|1|2|3|4\fR
|
||||||
|
.br
|
||||||
|
Privacy level used to collect Pi-hole statistics.
|
||||||
|
.br
|
||||||
|
0 - show everything
|
||||||
|
.br
|
||||||
|
1 - hide domains
|
||||||
|
.br
|
||||||
|
2 - hide domains and clients
|
||||||
|
.br
|
||||||
|
3 - anonymous mode (hide everything)
|
||||||
|
.br
|
||||||
|
4 - disable all statistics
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBIGNORE_LOCALHOST=no|yes\fR
|
||||||
|
.br
|
||||||
|
Should FTL ignore queries coming from the local machine?
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBAAAA_QUERY_ANALYSIS=yes|no\fR
|
||||||
|
.br
|
||||||
|
Should FTL analyze AAAA queries?
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBANALYZE_ONLY_A_AND_AAAA=false|true\fR
|
||||||
|
.br
|
||||||
|
Should FTL only analyze A and AAAA queries?
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBSOCKET_LISTENING=localonly|all\fR
|
||||||
|
.br
|
||||||
|
Listen only for local socket connections on the API port or permit all connections.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBFTLPORT=4711\fR
|
||||||
|
.br
|
||||||
|
On which port should FTL be listening?
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBRESOLVE_IPV6=yes|no\fR
|
||||||
|
.br
|
||||||
|
Should FTL try to resolve IPv6 addresses to hostnames?
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBRESOLVE_IPV4=yes|no\fR
|
||||||
|
.br
|
||||||
|
Should FTL try to resolve IPv4 addresses to hostnames?
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDELAY_STARTUP=0\fR
|
||||||
|
.br
|
||||||
|
Time in seconds (between 0 and 300) to delay FTL startup.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBNICE=-10\fR
|
||||||
|
.br
|
||||||
|
Set the niceness of the Pi-hole FTL process.
|
||||||
|
.br
|
||||||
|
Can be disabled altogether by setting a value of -999.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBNAMES_FROM_NETDB=true|false\fR
|
||||||
|
.br
|
||||||
|
Control whether FTL should use a fallback option and try to obtain client names from checking the network table.
|
||||||
|
.br
|
||||||
|
E.g. IPv6 clients without a hostname will be compared via MAC address to known clients.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB\fBREFRESH_HOSTNAMES=IPV4|ALL|NONE\fR
|
||||||
|
.br
|
||||||
|
Change how (and if) hourly PTR requests are made to check for changes in client and upstream server hostnames:
|
||||||
|
.br
|
||||||
|
IPV4 - Do the hourly PTR lookups only for IPv4 addresses resolving issues in networks with many short-lived PE IPv6 addresses.
|
||||||
|
.br
|
||||||
|
ALL - Do the hourly PTR lookups for all addresses. This can create a lot of PTR queries in networks with many IPv6 addresses.
|
||||||
|
.br
|
||||||
|
NONE - Don't do hourly PTR lookups. Look up hostnames once (when first seeing a client) and never again. Future hostname changes may be missed.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBMAXNETAGE=365\fR
|
||||||
|
.br
|
||||||
|
IP addresses (and associated host names) older than the specified number of days are removed.
|
||||||
|
.br
|
||||||
|
This avoids dead entries in the network overview table.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBEDNS0_ECS=true|false\fR
|
||||||
|
.br
|
||||||
|
Should we overwrite the query source when client information is provided through EDNS0 client subnet (ECS) information?
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBPARSE_ARP_CACHE=true|false\fR
|
||||||
|
.br
|
||||||
|
Parse ARP cache to fill network overview table.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDBIMPORT=yes|no\fR
|
||||||
|
.br
|
||||||
|
Should FTL load information from the database on startup to be aware of the most recent history?
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBMAXDBDAYS=365\fR
|
||||||
|
.br
|
||||||
|
How long should queries be stored in the database? Setting this to 0 disables the database
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDBINTERVAL=1.0\fR
|
||||||
|
.br
|
||||||
|
How often do we store queries in FTL's database [minutes]?
|
||||||
|
.br
|
||||||
|
Accepts value between 0.1 (6 sec) and 1440 (1 day)
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDBFILE=/etc/pihole/pihole-FTL.db\fR
|
||||||
|
.br
|
||||||
|
Specify path and filename of FTL's SQLite long-term database.
|
||||||
|
.br
|
||||||
|
Setting this to DBFILE= disables the database altogether
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBLOGFILE=/var/log/pihole-FTL.log\fR
|
||||||
|
.br
|
||||||
|
The location of FTL's log file.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBPIDFILE=/run/pihole-FTL.pid\fR
|
||||||
|
.br
|
||||||
|
The file which contains the PID of FTL's main process.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBPORTFILE=/run/pihole-FTL.port\fR
|
||||||
|
.br
|
||||||
|
Specify path and filename where the FTL process will write its API port number.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBSOCKETFILE=/run/pihole/FTL.sock\fR
|
||||||
|
.br
|
||||||
|
The file containing the socket FTL's API is listening on.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBSETUPVARSFILE=/etc/pihole/setupVars.conf\fR
|
||||||
|
.br
|
||||||
|
The config file of Pi-hole containing, e.g., the current blocking status (do not change).
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBMACVENDORDB=/etc/pihole/macvendor.db\fR
|
||||||
|
.br
|
||||||
|
The database containing MAC -> Vendor information for the network table.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBGRAVITYDB=/etc/pihole/gravity.db\fR
|
||||||
|
.br
|
||||||
|
Specify path and filename of FTL's SQLite3 gravity database. This database contains all domains relevant for Pi-hole's DNS blocking.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDEBUG_ALL=false|true\fR
|
||||||
|
.br
|
||||||
|
Enable all debug flags. If this is set to true, all other debug config options are ignored.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDEBUG_DATABASE=false|true\fR
|
||||||
|
.br
|
||||||
|
Print debugging information about database actions such as SQL statements and performance.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDEBUG_NETWORKING=false|true\fR
|
||||||
|
.br
|
||||||
|
Prints a list of the detected network interfaces on the startup of FTL.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDEBUG_LOCKS=false|true\fR
|
||||||
|
.br
|
||||||
|
Print information about shared memory locks.
|
||||||
|
.br
|
||||||
|
Messages will be generated when waiting, obtaining, and releasing a lock.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDEBUG_QUERIES=false|true\fR
|
||||||
|
.br
|
||||||
|
Print extensive DNS query information (domains, types, replies, etc.).
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDEBUG_FLAGS=false|true\fR
|
||||||
|
.br
|
||||||
|
Print flags of queries received by the DNS hooks.
|
||||||
|
.br
|
||||||
|
Only effective when \fBDEBUG_QUERIES\fR is enabled as well.
|
||||||
|
|
||||||
|
\fBDEBUG_SHMEM=false|true\fR
|
||||||
|
.br
|
||||||
|
Print information about shared memory buffers.
|
||||||
|
.br
|
||||||
|
Messages are either about creating or enlarging shmem objects or string injections.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDEBUG_GC=false|true\fR
|
||||||
|
.br
|
||||||
|
Print information about garbage collection (GC):
|
||||||
|
.br
|
||||||
|
What is to be removed, how many have been removed and how long did GC take.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDEBUG_ARP=false|true\fR
|
||||||
|
.br
|
||||||
|
Print information about ARP table processing:
|
||||||
|
.br
|
||||||
|
How long did parsing take, whether read MAC addresses are valid, and if the macvendor.db file exists.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDEBUG_REGEX=false|true\fR
|
||||||
|
.br
|
||||||
|
Controls if FTL should print extended details about regex matching.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDEBUG_API=false|true\fR
|
||||||
|
.br
|
||||||
|
Print extra debugging information during telnet API calls.
|
||||||
|
.br
|
||||||
|
Currently only used to send extra information when getting all queries.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDEBUG_OVERTIME=false|true\fR
|
||||||
|
.br
|
||||||
|
Print information about overTime memory operations, such as initializing or moving overTime slots.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDEBUG_EXTBLOCKED=false|true\fR
|
||||||
|
.br
|
||||||
|
Print information about why FTL decided that certain queries were recognized as being externally blocked.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDEBUG_CAPS=false|true\fR
|
||||||
|
.br
|
||||||
|
Print information about POSIX capabilities granted to the FTL process.
|
||||||
|
.br
|
||||||
|
The current capabilities are printed on receipt of SIGHUP i.e. after executing `killall -HUP pihole-FTL`.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDEBUG_DNSMASQ_LINES=false|true\fR
|
||||||
|
.br
|
||||||
|
Print file and line causing a dnsmasq event into FTL's log files.
|
||||||
|
.br
|
||||||
|
This is handy to implement additional hooks missing from FTL.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDEBUG_VECTORS=false|true\fR
|
||||||
|
.br
|
||||||
|
FTL uses dynamically allocated vectors for various tasks.
|
||||||
|
.br
|
||||||
|
This config option enables extensive debugging information such as information about allocation, referencing, deletion, and appending.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBDEBUG_RESOLVER=false|true\fR
|
||||||
|
.br
|
||||||
|
Extensive information about hostname resolution like which DNS servers are used in the first and second hostname resolving tries.
|
||||||
|
.br
|
||||||
|
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
|
||||||
|
\fBpihole\fR(8), \fBpihole-FTL\fR(8)
|
||||||
|
.br
|
||||||
|
.SH "COLOPHON"
|
||||||
|
|
||||||
|
Pi-hole : The Faster-Than-Light (FTL) Engine is a lightweight, purpose-built daemon used to provide statistics needed for the Pi-hole Web Interface, and its API can be easily integrated into your own projects. Although it is an optional component of the Pi-hole ecosystem, it will be installed by default to provide statistics. As the name implies, FTL does its work \fIvery quickly\fR!
|
||||||
|
.br
|
||||||
|
|
||||||
|
Get sucked into the latest news and community activity by entering Pi-hole's orbit. Information about Pi-hole, and the latest version of the software can be found at https://pi-hole.net
|
||||||
|
.br
|
||||||
379
manpages/pihole.8
Normal file
379
manpages/pihole.8
Normal file
@@ -0,0 +1,379 @@
|
|||||||
|
.TH "Pi-hole" "8" "Pi-hole" "Pi-hole" "April 2020"
|
||||||
|
.SH "NAME"
|
||||||
|
|
||||||
|
Pi-hole : A black-hole for internet advertisements
|
||||||
|
.br
|
||||||
|
.SH "SYNOPSIS"
|
||||||
|
|
||||||
|
\fBpihole\fR (\fB-w\fR|\fB-b\fR|\fB--wild\fR|\fB--regex\fR) [options] domain(s)
|
||||||
|
.br
|
||||||
|
\fBpihole -a\fR \fB-p\fR password
|
||||||
|
.br
|
||||||
|
\fBpihole -a\fR (\fB-c|-f|-k\fR)
|
||||||
|
.br
|
||||||
|
\fBpihole -a -e\fR email
|
||||||
|
.br
|
||||||
|
\fBpihole -a -i\fR interface
|
||||||
|
.br
|
||||||
|
\fBpihole -a -l\fR privacylevel
|
||||||
|
.br
|
||||||
|
\fBpihole -c\fR [-j|-r|-e]
|
||||||
|
.br
|
||||||
|
\fBpihole\fR \fB-d\fR [-a]
|
||||||
|
.br
|
||||||
|
\fBpihole -f
|
||||||
|
.br
|
||||||
|
pihole -r
|
||||||
|
.br
|
||||||
|
pihole -t
|
||||||
|
.br
|
||||||
|
pihole -g\fR
|
||||||
|
.br
|
||||||
|
\fBpihole\fR -\fBq\fR [options]
|
||||||
|
.br
|
||||||
|
\fBpihole\fR \fB-l\fR (\fBon|off|off noflush\fR)
|
||||||
|
.br
|
||||||
|
\fBpihole -up \fR[--check-only]
|
||||||
|
.br
|
||||||
|
\fBpihole -v\fR [-p|-a|-f] [-c|-l|-hash]
|
||||||
|
.br
|
||||||
|
\fBpihole uninstall
|
||||||
|
.br
|
||||||
|
pihole status
|
||||||
|
.br
|
||||||
|
pihole restartdns\fR [options]
|
||||||
|
.br
|
||||||
|
\fBpihole\fR (\fBenable\fR|\fBdisable\fR [time])
|
||||||
|
.br
|
||||||
|
\fBpihole\fR \fBcheckout\fR repo [branch]
|
||||||
|
.br
|
||||||
|
\fBpihole\fR \fBhelp\fR
|
||||||
|
.br
|
||||||
|
.SH "DESCRIPTION"
|
||||||
|
|
||||||
|
Available commands and options:
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-w, whitelist\fR [options] [<domain1> <domain2 ...>]
|
||||||
|
.br
|
||||||
|
Adds or removes specified domain or domains to the Whitelist
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-b, blacklist\fR [options] [<domain1> <domain2 ...>]
|
||||||
|
.br
|
||||||
|
Adds or removes specified domain or domains to the blacklist
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB--regex, regex\fR [options] [<regex1> <regex2 ...>]
|
||||||
|
.br
|
||||||
|
Add or removes specified regex filter to the regex blacklist
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB--white-regex\fR [options] [<regex1> <regex2 ...>]
|
||||||
|
.br
|
||||||
|
Add or removes specified regex filter to the regex whitelist
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB--wild, wildcard\fR [options] [<domain1> <domain2 ...>]
|
||||||
|
.br
|
||||||
|
Add or removes specified domain to the wildcard blacklist
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB--white-wild\fR [options] [<domain1> <domain2 ...>]
|
||||||
|
.br
|
||||||
|
Add or removes specified domain to the wildcard whitelist
|
||||||
|
.br
|
||||||
|
|
||||||
|
(Whitelist/Blacklist manipulation options):
|
||||||
|
.br
|
||||||
|
-d, --delmode Remove domain(s) from the list
|
||||||
|
.br
|
||||||
|
-nr, --noreload Update list without refreshing dnsmasq
|
||||||
|
.br
|
||||||
|
-q, --quiet Make output less verbose
|
||||||
|
.br
|
||||||
|
-l, --list Display all your listed domains
|
||||||
|
.br
|
||||||
|
--nuke Removes all entries in a list
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-d, debug\fR [-a]
|
||||||
|
.br
|
||||||
|
Start a debugging session
|
||||||
|
.br
|
||||||
|
|
||||||
|
-a Enable automated debugging
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-f, flush\fR
|
||||||
|
.br
|
||||||
|
Flush the Pi-hole log
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-r, reconfigure\fR
|
||||||
|
.br
|
||||||
|
Reconfigure or Repair Pi-hole subsystems
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-t, tail\fR
|
||||||
|
.br
|
||||||
|
View the live output of the Pi-hole log
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-a, admin\fR [options]
|
||||||
|
.br
|
||||||
|
|
||||||
|
(Admin options):
|
||||||
|
.br
|
||||||
|
-p, password Set Web Interface password
|
||||||
|
.br
|
||||||
|
-c, celsius Set Celsius as preferred temperature unit
|
||||||
|
.br
|
||||||
|
-f, fahrenheit Set Fahrenheit as preferred temperature unit
|
||||||
|
.br
|
||||||
|
-k, kelvin Set Kelvin as preferred temperature unit
|
||||||
|
.br
|
||||||
|
-e, email Set an administrative contact address for the
|
||||||
|
Block Page
|
||||||
|
.br
|
||||||
|
-i, interface Specify dnsmasq's interface listening behavior
|
||||||
|
.br
|
||||||
|
-l, privacylevel <level> Set privacy level
|
||||||
|
(0 = lowest, 3 = highest)
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-c, chronometer\fR [options]
|
||||||
|
.br
|
||||||
|
Calculates stats and displays to an LCD
|
||||||
|
.br
|
||||||
|
|
||||||
|
(Chronometer Options):
|
||||||
|
.br
|
||||||
|
-j, --json Output stats as JSON formatted string
|
||||||
|
.br
|
||||||
|
-r, --refresh Set update frequency (in seconds)
|
||||||
|
.br
|
||||||
|
-e, --exit Output stats and exit without refreshing
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-g, updateGravity\fR
|
||||||
|
.br
|
||||||
|
Update the list of ad-serving domains
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-q, query\fR [option]
|
||||||
|
.br
|
||||||
|
Query the adlists for a specified domain
|
||||||
|
.br
|
||||||
|
|
||||||
|
(Query options):
|
||||||
|
.br
|
||||||
|
-adlist Print the name of the block list URL
|
||||||
|
.br
|
||||||
|
-exact Search the block lists for exact domain matches
|
||||||
|
.br
|
||||||
|
-all Return all query matches within a block list
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-h, --help, help\fR
|
||||||
|
.br
|
||||||
|
Show a help dialog
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-l, logging\fR [on|off|off noflush]
|
||||||
|
.br
|
||||||
|
Specify whether the Pi-hole log should be used
|
||||||
|
.br
|
||||||
|
|
||||||
|
(Logging options):
|
||||||
|
.br
|
||||||
|
on Enable the Pi-hole log at /var/log/pihole.log
|
||||||
|
.br
|
||||||
|
off Disable and flush the Pi-hole log at
|
||||||
|
/var/log/pihole.log
|
||||||
|
.br
|
||||||
|
off noflush Disable the Pi-hole log at /var/log/pihole.log
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-up, updatePihole\fR [--check-only]
|
||||||
|
.br
|
||||||
|
Update Pi-hole subsystems
|
||||||
|
.br
|
||||||
|
|
||||||
|
--check-only Exit script before update is performed.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fB-v, version\fR [repo] [options]
|
||||||
|
.br
|
||||||
|
Show installed versions of Pi-hole, Web Interface & FTL
|
||||||
|
.br
|
||||||
|
|
||||||
|
.br
|
||||||
|
(repo options):
|
||||||
|
.br
|
||||||
|
-p, --pihole Only retrieve info regarding Pi-hole repository
|
||||||
|
.br
|
||||||
|
-a, --admin Only retrieve info regarding AdminLTE
|
||||||
|
repository
|
||||||
|
.br
|
||||||
|
-f, --ftl Only retrieve info regarding FTL repository
|
||||||
|
.br
|
||||||
|
(version options):
|
||||||
|
.br
|
||||||
|
-c, --current Return the current version
|
||||||
|
.br
|
||||||
|
-l, --latest Return the latest version
|
||||||
|
.br
|
||||||
|
--hash Return the GitHub hash from your local
|
||||||
|
repositories
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBuninstall\fR
|
||||||
|
.br
|
||||||
|
Uninstall Pi-hole from your system
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBstatus\fR
|
||||||
|
.br
|
||||||
|
Display the running status of Pi-hole subsystems
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBenable\fR
|
||||||
|
.br
|
||||||
|
Enable Pi-hole subsystems
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBdisable\fR [time]
|
||||||
|
.br
|
||||||
|
Disable Pi-hole subsystems, optionally for a set duration
|
||||||
|
.br
|
||||||
|
|
||||||
|
(time options):
|
||||||
|
.br
|
||||||
|
#s Disable Pi-hole functionality for # second(s)
|
||||||
|
.br
|
||||||
|
#m Disable Pi-hole functionality for # minute(s)
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBrestartdns\fR [options]
|
||||||
|
.br
|
||||||
|
Full restart Pi-hole subsystems. Without any options (see below) a full restart causes config file parsing and history re-reading
|
||||||
|
.br
|
||||||
|
|
||||||
|
(restart options):
|
||||||
|
.br
|
||||||
|
reload Updates the lists (incl. HOSTS files) and flushes DNS cache. Does not reparse config files
|
||||||
|
.br
|
||||||
|
reload-lists Updates the lists (excl. HOSTS files) WITHOUT flushing the DNS cache. Does not reparse config files
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBcheckout\fR [repo] [branch]
|
||||||
|
.br
|
||||||
|
Switch Pi-hole subsystems to a different GitHub branch
|
||||||
|
.br
|
||||||
|
|
||||||
|
(repo options):
|
||||||
|
.br
|
||||||
|
core Change the branch of Pi-hole's core subsystem
|
||||||
|
.br
|
||||||
|
web Change the branch of Admin Console subsystem
|
||||||
|
.br
|
||||||
|
ftl Change the branch of Pi-hole's FTL subsystem
|
||||||
|
.br
|
||||||
|
(branch options):
|
||||||
|
.br
|
||||||
|
master Update subsystems to the latest stable release
|
||||||
|
.br
|
||||||
|
dev Update subsystems to the latest development
|
||||||
|
release
|
||||||
|
.br
|
||||||
|
branchname Update subsystems to the specified branchname
|
||||||
|
.br
|
||||||
|
.SH "EXAMPLE"
|
||||||
|
|
||||||
|
Some usage examples
|
||||||
|
.br
|
||||||
|
|
||||||
|
Whitelist/blacklist manipulation
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole -w iloveads.example.com\fR
|
||||||
|
.br
|
||||||
|
Adds "iloveads.example.com" to whitelist
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole -b -d noads.example.com\fR
|
||||||
|
.br
|
||||||
|
Removes "noads.example.com" from blacklist
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole --wild example.com\fR
|
||||||
|
.br
|
||||||
|
Adds example.com as a wildcard - would block all subdomains of
|
||||||
|
example.com, including example.com itself.
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole --regex "ad.*\\.example\\.com$"\fR
|
||||||
|
.br
|
||||||
|
Adds "ad.*\\.example\\.com$" to the regex blacklist.
|
||||||
|
Would block all subdomains of example.com which start with "ad"
|
||||||
|
.br
|
||||||
|
|
||||||
|
Changing the Web Interface password
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole -a -p ExamplePassword\fR
|
||||||
|
.br
|
||||||
|
Change the password to "ExamplePassword"
|
||||||
|
.br
|
||||||
|
|
||||||
|
Updating lists from internet sources
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole -g\fR
|
||||||
|
.br
|
||||||
|
Update the list of ad-serving domains
|
||||||
|
.br
|
||||||
|
|
||||||
|
Displaying version information
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole -v -a -c\fR
|
||||||
|
.br
|
||||||
|
Display the current version of AdminLTE
|
||||||
|
.br
|
||||||
|
|
||||||
|
Temporarily disabling Pi-hole
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole disable 5m\fR
|
||||||
|
.br
|
||||||
|
Disable Pi-hole functionality for five minutes
|
||||||
|
.br
|
||||||
|
|
||||||
|
Switching Pi-hole subsystem branches
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole checkout master\fR
|
||||||
|
.br
|
||||||
|
Switch to master branch
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole checkout core dev\fR
|
||||||
|
.br
|
||||||
|
Switch to core development branch
|
||||||
|
.br
|
||||||
|
|
||||||
|
\fBpihole arpflush\fR
|
||||||
|
.br
|
||||||
|
Flush information stored in Pi-hole's network tables
|
||||||
|
.br
|
||||||
|
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
|
||||||
|
\fBlighttpd\fR(8), \fBpihole-FTL\fR(8)
|
||||||
|
.br
|
||||||
|
.SH "COLOPHON"
|
||||||
|
|
||||||
|
Get sucked into the latest news and community activity by entering Pi-hole's orbit. Information about Pi-hole, and the latest version of the software can be found at https://pi-hole.net.
|
||||||
|
.br
|
||||||
542
pihole
Executable file
542
pihole
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.
|
||||||
|
#
|
||||||
|
# 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"
|
||||||
|
|
||||||
|
# setupVars and PI_HOLE_BIN_DIR are not readonly here because in some functions (checkout),
|
||||||
|
# they might get set again when the installer is sourced. This causes an
|
||||||
|
# error due to modifying a readonly variable.
|
||||||
|
setupVars="/etc/pihole/setupVars.conf"
|
||||||
|
PI_HOLE_BIN_DIR="/usr/local/bin"
|
||||||
|
readonly FTL_PID_FILE="/run/pihole-FTL.pid"
|
||||||
|
|
||||||
|
readonly colfile="${PI_HOLE_SCRIPT_DIR}/COL_TABLE"
|
||||||
|
source "${colfile}"
|
||||||
|
|
||||||
|
webpageFunc() {
|
||||||
|
source "${PI_HOLE_SCRIPT_DIR}/webpage.sh"
|
||||||
|
main "$@"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
listFunc() {
|
||||||
|
"${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
|
||||||
|
}
|
||||||
|
|
||||||
|
arpFunc() {
|
||||||
|
"${PI_HOLE_SCRIPT_DIR}"/piholeARPTable.sh "$@"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePiholeFunc() {
|
||||||
|
shift
|
||||||
|
"${PI_HOLE_SCRIPT_DIR}"/update.sh "$@"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
reconfigurePiholeFunc() {
|
||||||
|
/etc/.pihole/automated\ install/basic-install.sh --reconfigure
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateGravityFunc() {
|
||||||
|
exec "${PI_HOLE_SCRIPT_DIR}"/gravity.sh "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
queryFunc() {
|
||||||
|
shift
|
||||||
|
"${PI_HOLE_SCRIPT_DIR}"/query.sh "$@"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
chronometerFunc() {
|
||||||
|
shift
|
||||||
|
"${PI_HOLE_SCRIPT_DIR}"/chronometer.sh "$@"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uninstallFunc() {
|
||||||
|
"${PI_HOLE_SCRIPT_DIR}"/uninstall.sh
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
versionFunc() {
|
||||||
|
shift
|
||||||
|
exec "${PI_HOLE_SCRIPT_DIR}"/version.sh "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get PID of main pihole-FTL process
|
||||||
|
getFTLPID() {
|
||||||
|
local pid
|
||||||
|
|
||||||
|
if [ -s "${FTL_PID_FILE}" ]; then
|
||||||
|
# -s: FILE exists and has a size greater than zero
|
||||||
|
pid="$(<"$FTL_PID_FILE")"
|
||||||
|
# Exploit prevention: unset the variable if there is malicious content
|
||||||
|
# Verify that the value read from the file is numeric
|
||||||
|
[[ "$pid" =~ [^[:digit:]] ]] && unset pid
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If FTL is not running, or the PID file contains malicious stuff, substitute
|
||||||
|
# negative PID to signal this to the caller
|
||||||
|
echo "${pid:=-1}"
|
||||||
|
}
|
||||||
|
|
||||||
|
restartDNS() {
|
||||||
|
local svcOption svc str output status pid icon
|
||||||
|
svcOption="${1:-restart}"
|
||||||
|
|
||||||
|
# Determine if we should reload or restart
|
||||||
|
if [[ "${svcOption}" =~ "reload-lists" ]]; then
|
||||||
|
# Reloading of the lists has been requested
|
||||||
|
# Note 1: This will NOT re-read any *.conf files
|
||||||
|
# Note 2: We cannot use killall here as it does
|
||||||
|
# not know about real-time signals
|
||||||
|
pid="$(getFTLPID)"
|
||||||
|
if [[ "$pid" -eq "-1" ]]; then
|
||||||
|
svc="true"
|
||||||
|
str="FTL is not running"
|
||||||
|
icon="${INFO}"
|
||||||
|
else
|
||||||
|
svc="kill -RTMIN ${pid}"
|
||||||
|
str="Reloading DNS lists"
|
||||||
|
icon="${TICK}"
|
||||||
|
fi
|
||||||
|
elif [[ "${svcOption}" =~ "reload" ]]; then
|
||||||
|
# Reloading of the DNS cache has been requested
|
||||||
|
# Note: This will NOT re-read any *.conf files
|
||||||
|
pid="$(getFTLPID)"
|
||||||
|
if [[ "$pid" -eq "-1" ]]; then
|
||||||
|
svc="true"
|
||||||
|
str="FTL is not running"
|
||||||
|
icon="${INFO}"
|
||||||
|
else
|
||||||
|
svc="kill -HUP ${pid}"
|
||||||
|
str="Flushing DNS cache"
|
||||||
|
icon="${TICK}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# A full restart has been requested
|
||||||
|
svc="service pihole-FTL restart"
|
||||||
|
str="Restarting DNS server"
|
||||||
|
icon="${TICK}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Print output to Terminal, but not to Web Admin
|
||||||
|
[[ -t 1 ]] && echo -ne " ${INFO} ${str}..."
|
||||||
|
|
||||||
|
output=$( { ${svc}; } 2>&1 )
|
||||||
|
status="$?"
|
||||||
|
|
||||||
|
if [[ "${status}" -eq 0 ]]; then
|
||||||
|
[[ -t 1 ]] && echo -e "${OVER} ${icon} ${str}"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
[[ ! -t 1 ]] && local OVER=""
|
||||||
|
echo -e "${OVER} ${CROSS} ${output}"
|
||||||
|
return 1
|
||||||
|
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
|
||||||
|
if grep -cq "BLOCKING_ENABLED=false" "${setupVars}"; then
|
||||||
|
echo -e " ${INFO} Blocking already disabled, nothing to do"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
if [[ $# > 1 ]]; then
|
||||||
|
local error=false
|
||||||
|
if [[ "${2}" == *"s" ]]; then
|
||||||
|
tt=${2%"s"}
|
||||||
|
if [[ "${tt}" =~ ^-?[0-9]+$ ]];then
|
||||||
|
local str="Disabling blocking for ${tt} seconds"
|
||||||
|
echo -e " ${INFO} ${str}..."
|
||||||
|
local str="Blocking will be re-enabled in ${tt} seconds"
|
||||||
|
nohup "${PI_HOLE_SCRIPT_DIR}"/pihole-reenable.sh ${tt} </dev/null &>/dev/null &
|
||||||
|
else
|
||||||
|
local error=true
|
||||||
|
fi
|
||||||
|
elif [[ "${2}" == *"m" ]]; then
|
||||||
|
tt=${2%"m"}
|
||||||
|
if [[ "${tt}" =~ ^-?[0-9]+$ ]];then
|
||||||
|
local str="Disabling blocking for ${tt} minutes"
|
||||||
|
echo -e " ${INFO} ${str}..."
|
||||||
|
local str="Blocking will be re-enabled in ${tt} minutes"
|
||||||
|
tt=$((${tt}*60))
|
||||||
|
nohup "${PI_HOLE_SCRIPT_DIR}"/pihole-reenable.sh ${tt} </dev/null &>/dev/null &
|
||||||
|
else
|
||||||
|
local error=true
|
||||||
|
fi
|
||||||
|
elif [[ -n "${2}" ]]; then
|
||||||
|
local error=true
|
||||||
|
else
|
||||||
|
echo -e " ${INFO} Disabling blocking"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${error} == true ]];then
|
||||||
|
echo -e " ${COL_LIGHT_RED}Unknown format for delayed reactivation of the blocking!${COL_NC}"
|
||||||
|
echo -e " Try 'pihole disable --help' for more information."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local str="Pi-hole Disabled"
|
||||||
|
sed -i "/BLOCKING_ENABLED=/d" "${setupVars}"
|
||||||
|
echo "BLOCKING_ENABLED=false" >> "${setupVars}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Enable Pi-hole
|
||||||
|
killall -q pihole-reenable
|
||||||
|
if grep -cq "BLOCKING_ENABLED=true" "${setupVars}"; then
|
||||||
|
echo -e " ${INFO} Blocking already enabled, nothing to do"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo -e " ${INFO} Enabling blocking"
|
||||||
|
local str="Pi-hole Enabled"
|
||||||
|
|
||||||
|
sed -i "/BLOCKING_ENABLED=/d" "${setupVars}"
|
||||||
|
echo "BLOCKING_ENABLED=true" >> "${setupVars}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
restartDNS reload-lists
|
||||||
|
|
||||||
|
echo -e "${OVER} ${TICK} ${str}"
|
||||||
|
}
|
||||||
|
|
||||||
|
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 and flush the Pi-hole log at /var/log/pihole.log
|
||||||
|
off noflush 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
|
||||||
|
if [[ "${2}" != "noflush" ]]; then
|
||||||
|
# Flush logs
|
||||||
|
"${PI_HOLE_BIN_DIR}"/pihole -f
|
||||||
|
fi
|
||||||
|
echo -e " ${INFO} Disabling logging..."
|
||||||
|
local str="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 -e " ${INFO} Enabling logging..."
|
||||||
|
local str="Logging has been enabled!"
|
||||||
|
else
|
||||||
|
echo -e " ${COL_LIGHT_RED}Invalid option${COL_NC}
|
||||||
|
Try 'pihole logging --help' for more information."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
restartDNS
|
||||||
|
echo -e "${OVER} ${TICK} ${str}"
|
||||||
|
}
|
||||||
|
|
||||||
|
analyze_ports() {
|
||||||
|
local lv4 lv6 port=${1}
|
||||||
|
# FTL is listening at least on at least one port when this
|
||||||
|
# function is getting called
|
||||||
|
# Check individual address family/protocol combinations
|
||||||
|
# For a healthy Pi-hole, they should all be up (nothing printed)
|
||||||
|
lv4="$(ss --ipv4 --listening --numeric --tcp --udp src :${port})"
|
||||||
|
if grep -q "udp " <<< "${lv4}"; then
|
||||||
|
echo -e " ${TICK} UDP (IPv4)"
|
||||||
|
else
|
||||||
|
echo -e " ${CROSS} UDP (IPv4)"
|
||||||
|
fi
|
||||||
|
if grep -q "tcp " <<< "${lv4}"; then
|
||||||
|
echo -e " ${TICK} TCP (IPv4)"
|
||||||
|
else
|
||||||
|
echo -e " ${CROSS} TCP (IPv4)"
|
||||||
|
fi
|
||||||
|
lv6="$(ss --ipv6 --listening --numeric --tcp --udp src :${port})"
|
||||||
|
if grep -q "udp " <<< "${lv6}"; then
|
||||||
|
echo -e " ${TICK} UDP (IPv6)"
|
||||||
|
else
|
||||||
|
echo -e " ${CROSS} UDP (IPv6)"
|
||||||
|
fi
|
||||||
|
if grep -q "tcp " <<< "${lv6}"; then
|
||||||
|
echo -e " ${TICK} TCP (IPv6)"
|
||||||
|
else
|
||||||
|
echo -e " ${CROSS} TCP (IPv6)"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
statusFunc() {
|
||||||
|
# Determine if there is pihole-FTL service is listening
|
||||||
|
local listening pid port
|
||||||
|
|
||||||
|
pid="$(getFTLPID)"
|
||||||
|
if [[ "$pid" -eq "-1" ]]; then
|
||||||
|
case "${1}" in
|
||||||
|
"web") echo "-1";;
|
||||||
|
*) echo -e " ${CROSS} DNS service is NOT running";;
|
||||||
|
esac
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
#get the port pihole-FTL is listening on by using FTL's telnet API
|
||||||
|
port="$(echo ">dns-port >quit" | nc 127.0.0.1 4711)"
|
||||||
|
if [[ "${port}" == "0" ]]; then
|
||||||
|
case "${1}" in
|
||||||
|
"web") echo "-1";;
|
||||||
|
*) echo -e " ${CROSS} DNS service is NOT listening";;
|
||||||
|
esac
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
if [[ "${1}" != "web" ]]; then
|
||||||
|
echo -e " ${TICK} FTL is listening on port ${port}"
|
||||||
|
analyze_ports "${port}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine if Pi-hole's blocking is enabled
|
||||||
|
if grep -q "BLOCKING_ENABLED=false" /etc/pihole/setupVars.conf; then
|
||||||
|
# A config is commented out
|
||||||
|
case "${1}" in
|
||||||
|
"web") echo 0;;
|
||||||
|
*) echo -e " ${CROSS} Pi-hole blocking is disabled";;
|
||||||
|
esac
|
||||||
|
elif grep -q "BLOCKING_ENABLED=true" /etc/pihole/setupVars.conf; then
|
||||||
|
# Configs are set
|
||||||
|
case "${1}" in
|
||||||
|
"web") echo "$port";;
|
||||||
|
*) echo -e " ${TICK} Pi-hole blocking is enabled";;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
# No configs were found
|
||||||
|
case "${1}" in
|
||||||
|
"web") echo -2;;
|
||||||
|
*) echo -e " ${INFO} Pi-hole blocking will be enabled";;
|
||||||
|
esac
|
||||||
|
# Enable blocking
|
||||||
|
"${PI_HOLE_BIN_DIR}"/pihole enable
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
tailFunc() {
|
||||||
|
# Warn user if Pi-hole's logging is disabled
|
||||||
|
local logging_enabled=$(grep -c "^log-queries" /etc/dnsmasq.d/01-pihole.conf)
|
||||||
|
if [[ "${logging_enabled}" == "0" ]]; then
|
||||||
|
# No "log-queries" lines are found.
|
||||||
|
# Commented out lines (such as "#log-queries") are ignored
|
||||||
|
echo " ${CROSS} Warning: Query logging is disabled"
|
||||||
|
fi
|
||||||
|
echo -e " ${INFO} Press Ctrl-C to exit"
|
||||||
|
|
||||||
|
# Strip date from each line
|
||||||
|
# Color blocklist/blacklist/wildcard entries as red
|
||||||
|
# Color A/AAAA/DHCP strings as white
|
||||||
|
# Color everything else as gray
|
||||||
|
tail -f /var/log/pihole.log | grep --line-buffered "${1}" | sed -E \
|
||||||
|
-e "s,($(date +'%b %d ')| dnsmasq\[[0-9]*\]),,g" \
|
||||||
|
-e "s,(.*(blacklisted |gravity blocked ).*),${COL_RED}&${COL_NC}," \
|
||||||
|
-e "s,.*(query\\[A|DHCP).*,${COL_NC}&${COL_NC}," \
|
||||||
|
-e "s,.*,${COL_GRAY}&${COL_NC},"
|
||||||
|
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 Web Interface subsystem
|
||||||
|
ftl [branch] Change the branch of Pi-hole's FTL subsystem
|
||||||
|
|
||||||
|
Branches:
|
||||||
|
master Update subsystems to the latest stable release
|
||||||
|
dev Update subsystems to the latest development release
|
||||||
|
branchname Update subsystems to the specified branchname"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
source "${PI_HOLE_SCRIPT_DIR}"/piholeCheckout.sh
|
||||||
|
shift
|
||||||
|
checkout "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
tricorderFunc() {
|
||||||
|
local tricorder_token
|
||||||
|
if [[ ! -p "/dev/stdin" ]]; then
|
||||||
|
echo -e " ${INFO} Please do not call Tricorder directly"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
tricorder_token=$(curl --silent --fail --show-error --upload-file "-" https://tricorder.pi-hole.net/upload < /dev/stdin 2>&1)
|
||||||
|
if [[ "${tricorder_token}" != "https://tricorder.pi-hole.net/"* ]]; then
|
||||||
|
echo -e "${CROSS} uploading failed, contact Pi-hole support for assistance."
|
||||||
|
# Log curl error (if available)
|
||||||
|
if [ -n "${tricorder_token}" ]; then
|
||||||
|
echo -e "${INFO} Error message: ${COL_RED}${tricorder_token}${COL_NC}\\n"
|
||||||
|
tricorder_token=""
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Upload successful, your token is: ${COL_GREEN}${tricorder_token}${COL_NC}"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCheckFunc() {
|
||||||
|
"${PI_HOLE_SCRIPT_DIR}"/updatecheck.sh "$@"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
--regex, regex Regex blacklist domains(s)
|
||||||
|
--white-regex Regex whitelist domains(s)
|
||||||
|
--wild, wildcard Wildcard blacklist domain(s)
|
||||||
|
--white-wild Wildcard whitelist domain(s)
|
||||||
|
Add '-h' for more info on whitelist/blacklist usage
|
||||||
|
|
||||||
|
Debugging Options:
|
||||||
|
-d, debug Start a debugging session
|
||||||
|
Add '-a' to automatically upload the log to tricorder.pi-hole.net
|
||||||
|
-f, flush Flush the Pi-hole log
|
||||||
|
-r, reconfigure Reconfigure or Repair Pi-hole subsystems
|
||||||
|
-t, tail [arg] View the live output of the Pi-hole log.
|
||||||
|
Add an optional argument to filter the log
|
||||||
|
(regular expressions are supported)
|
||||||
|
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-a, admin Web interface options
|
||||||
|
Add '-h' for more info on Web Interface 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 '-h' for more info on query usage
|
||||||
|
-up, updatePihole Update Pi-hole subsystems
|
||||||
|
Add '--check-only' to exit script before update is performed.
|
||||||
|
-v, version Show installed versions of Pi-hole, Web Interface & 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 Full restart Pi-hole subsystems
|
||||||
|
Add 'reload' to update the lists and flush the cache without restarting the DNS server
|
||||||
|
Add 'reload-lists' to only update the lists WITHOUT flushing the cache or restarting the DNS server
|
||||||
|
checkout Switch Pi-hole subsystems to a different GitHub branch
|
||||||
|
Add '-h' for more info on checkout usage
|
||||||
|
arpflush Flush information stored in Pi-hole's network tables";
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ $# = 0 ]]; then
|
||||||
|
helpFunc
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "${1}" in
|
||||||
|
"-h" | "help" | "--help" ) helpFunc;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# 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 -e " ${CROSS} sudo is needed to run pihole commands. Please run this script as root or install sudo."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Handle redirecting to specific functions based on arguments
|
||||||
|
case "${1}" in
|
||||||
|
"-w" | "whitelist" ) listFunc "$@";;
|
||||||
|
"-b" | "blacklist" ) listFunc "$@";;
|
||||||
|
"--wild" | "wildcard" ) listFunc "$@";;
|
||||||
|
"--regex" | "regex" ) listFunc "$@";;
|
||||||
|
"--white-regex" | "white-regex" ) listFunc "$@";;
|
||||||
|
"--white-wild" | "white-wild" ) listFunc "$@";;
|
||||||
|
"-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" ) statusFunc "$2";;
|
||||||
|
"restartdns" ) restartDNS "$2";;
|
||||||
|
"-a" | "admin" ) webpageFunc "$@";;
|
||||||
|
"-t" | "tail" ) tailFunc "$2";;
|
||||||
|
"checkout" ) piholeCheckoutFunc "$@";;
|
||||||
|
"tricorder" ) tricorderFunc;;
|
||||||
|
"updatechecker" ) updateCheckFunc "$@";;
|
||||||
|
"arpflush" ) arpFunc "$@";;
|
||||||
|
* ) helpFunc;;
|
||||||
|
esac
|
||||||
25
test/README.md
Normal file
25
test/README.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Recommended way to run tests
|
||||||
|
|
||||||
|
Make sure you have Docker and Python w/pip package manager.
|
||||||
|
|
||||||
|
From command line all you need to do is:
|
||||||
|
|
||||||
|
- `pip install tox`
|
||||||
|
- `tox`
|
||||||
|
|
||||||
|
Tox handles setting up a virtual environment for python dependencies, installing dependencies, building the docker images used by tests, and finally running tests. It's an easy way to have travis-ci like build behavior locally.
|
||||||
|
|
||||||
|
## Alternative py.test method of running tests
|
||||||
|
|
||||||
|
You're responsible for setting up your virtual env and dependencies in this situation.
|
||||||
|
|
||||||
|
```
|
||||||
|
py.test -vv -n auto -m "build_stage"
|
||||||
|
py.test -vv -n auto -m "not build_stage"
|
||||||
|
```
|
||||||
|
|
||||||
|
The build_stage tests have to run first to create the docker images, followed by the actual tests which utilize said images. Unless you're changing your dockerfiles you shouldn't have to run the build_stage every time - but it's a good idea to rebuild at least once a day in case the base Docker images or packages change.
|
||||||
|
|
||||||
|
# How do I debug python?
|
||||||
|
|
||||||
|
Highly recommended: Setup PyCharm on a **Docker enabled** machine. Having a python debugger like PyCharm changes your life if you've never used it :)
|
||||||
0
test/__init__.py
Normal file
0
test/__init__.py
Normal file
18
test/_centos_7.Dockerfile
Normal file
18
test/_centos_7.Dockerfile
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
FROM centos:7
|
||||||
|
RUN yum install -y git
|
||||||
|
|
||||||
|
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
|
||||||
|
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||||
|
|
||||||
|
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||||
18
test/_centos_8.Dockerfile
Normal file
18
test/_centos_8.Dockerfile
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
FROM centos:8
|
||||||
|
RUN yum install -y git
|
||||||
|
|
||||||
|
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
|
||||||
|
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||||
|
|
||||||
|
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||||
17
test/_debian_10.Dockerfile
Normal file
17
test/_debian_10.Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
FROM buildpack-deps:buster-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
|
||||||
|
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||||
|
|
||||||
|
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||||
17
test/_debian_11.Dockerfile
Normal file
17
test/_debian_11.Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
FROM buildpack-deps:bullseye-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
|
||||||
|
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||||
|
|
||||||
|
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||||
17
test/_debian_9.Dockerfile
Normal file
17
test/_debian_9.Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
FROM buildpack-deps:stretch-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
|
||||||
|
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||||
|
|
||||||
|
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||||
18
test/_fedora_33.Dockerfile
Normal file
18
test/_fedora_33.Dockerfile
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
FROM fedora:33
|
||||||
|
RUN dnf install -y git
|
||||||
|
|
||||||
|
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
|
||||||
|
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||||
|
|
||||||
|
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||||
18
test/_fedora_34.Dockerfile
Normal file
18
test/_fedora_34.Dockerfile
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
FROM fedora:34
|
||||||
|
RUN dnf install -y git
|
||||||
|
|
||||||
|
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
|
||||||
|
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||||
|
|
||||||
|
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||||
17
test/_ubuntu_16.Dockerfile
Normal file
17
test/_ubuntu_16.Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
FROM buildpack-deps:xenial-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
|
||||||
|
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||||
|
|
||||||
|
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||||
17
test/_ubuntu_18.Dockerfile
Normal file
17
test/_ubuntu_18.Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
FROM buildpack-deps:bionic-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
|
||||||
|
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||||
|
|
||||||
|
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||||
18
test/_ubuntu_20.Dockerfile
Normal file
18
test/_ubuntu_20.Dockerfile
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
FROM buildpack-deps:focal-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
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
RUN true && \
|
||||||
|
chmod +x $SCRIPTDIR/*
|
||||||
|
|
||||||
|
ENV PH_TEST true
|
||||||
|
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||||
|
|
||||||
|
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||||
18
test/_ubuntu_21.Dockerfile
Normal file
18
test/_ubuntu_21.Dockerfile
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
FROM buildpack-deps:hirsute-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
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
RUN true && \
|
||||||
|
chmod +x $SCRIPTDIR/*
|
||||||
|
|
||||||
|
ENV PH_TEST true
|
||||||
|
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||||
|
|
||||||
|
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||||
172
test/conftest.py
Normal file
172
test/conftest.py
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
import pytest
|
||||||
|
import testinfra
|
||||||
|
import testinfra.backend.docker
|
||||||
|
import subprocess
|
||||||
|
from textwrap import dedent
|
||||||
|
|
||||||
|
|
||||||
|
SETUPVARS = {
|
||||||
|
'PIHOLE_INTERFACE': 'eth99',
|
||||||
|
'PIHOLE_DNS_1': '4.2.2.1',
|
||||||
|
'PIHOLE_DNS_2': '4.2.2.2'
|
||||||
|
}
|
||||||
|
|
||||||
|
IMAGE = 'pytest_pihole:test_container'
|
||||||
|
|
||||||
|
tick_box = "[\x1b[1;32m\u2713\x1b[0m]"
|
||||||
|
cross_box = "[\x1b[1;31m\u2717\x1b[0m]"
|
||||||
|
info_box = "[i]"
|
||||||
|
|
||||||
|
|
||||||
|
# Monkeypatch sh to bash, if they ever support non hard code /bin/sh this can go away
|
||||||
|
# https://github.com/pytest-dev/pytest-testinfra/blob/master/testinfra/backend/docker.py
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
testinfra.backend.docker.DockerBackend.run = run_bash
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def host():
|
||||||
|
# run a container
|
||||||
|
docker_id = subprocess.check_output(
|
||||||
|
['docker', 'run', '-t', '-d', '--cap-add=ALL', IMAGE]).decode().strip()
|
||||||
|
|
||||||
|
# return a testinfra connection to the container
|
||||||
|
docker_host = testinfra.get_host("docker://" + docker_id)
|
||||||
|
|
||||||
|
yield docker_host
|
||||||
|
# at the end of the test suite, destroy the container
|
||||||
|
subprocess.check_call(['docker', 'rm', '-f', docker_id])
|
||||||
|
|
||||||
|
|
||||||
|
# Helper functions
|
||||||
|
def mock_command(script, args, container):
|
||||||
|
'''
|
||||||
|
Allows for setup of commands we don't really want to have to run for real
|
||||||
|
in unit tests
|
||||||
|
'''
|
||||||
|
full_script_path = '/usr/local/bin/{}'.format(script)
|
||||||
|
mock_script = dedent(r'''\
|
||||||
|
#!/bin/bash -e
|
||||||
|
echo "\$0 \$@" >> /var/log/{script}
|
||||||
|
case "\$1" in'''.format(script=script))
|
||||||
|
for k, v in args.items():
|
||||||
|
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_passthrough(script, args, container):
|
||||||
|
'''
|
||||||
|
Per other mock_command* functions, allows intercepting of commands we don't want to run for real
|
||||||
|
in unit tests, however also allows only specific arguments to be mocked. Anything not defined will
|
||||||
|
be passed through to the actual command.
|
||||||
|
|
||||||
|
Example use-case: mocking `git pull` but still allowing `git clone` to work as intended
|
||||||
|
'''
|
||||||
|
orig_script_path = container.check_output('command -v {}'.format(script))
|
||||||
|
full_script_path = '/usr/local/bin/{}'.format(script)
|
||||||
|
mock_script = dedent(r'''\
|
||||||
|
#!/bin/bash -e
|
||||||
|
echo "\$0 \$@" >> /var/log/{script}
|
||||||
|
case "\$1" in'''.format(script=script))
|
||||||
|
for k, v in args.items():
|
||||||
|
case = dedent('''
|
||||||
|
{arg})
|
||||||
|
echo {res}
|
||||||
|
exit {retcode}
|
||||||
|
;;'''.format(arg=k, res=v[0], retcode=v[1]))
|
||||||
|
mock_script += case
|
||||||
|
mock_script += dedent(r'''
|
||||||
|
*)
|
||||||
|
{orig_script_path} "\$@"
|
||||||
|
;;'''.format(orig_script_path=orig_script_path))
|
||||||
|
mock_script += dedent('''
|
||||||
|
esac''')
|
||||||
|
container.run('''
|
||||||
|
cat <<EOF> {script}\n{content}\nEOF
|
||||||
|
chmod +x {script}
|
||||||
|
rm -f /var/log/{scriptlog}'''.format(script=full_script_path,
|
||||||
|
content=mock_script,
|
||||||
|
scriptlog=script))
|
||||||
|
|
||||||
|
|
||||||
|
def mock_command_run(script, args, container):
|
||||||
|
'''
|
||||||
|
Allows for setup of commands we don't really want to have to run for real
|
||||||
|
in unit tests
|
||||||
|
'''
|
||||||
|
full_script_path = '/usr/local/bin/{}'.format(script)
|
||||||
|
mock_script = dedent(r'''\
|
||||||
|
#!/bin/bash -e
|
||||||
|
echo "\$0 \$@" >> /var/log/{script}
|
||||||
|
case "\$1 \$2" in'''.format(script=script))
|
||||||
|
for k, v in args.items():
|
||||||
|
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(r'''\
|
||||||
|
#!/bin/bash -e
|
||||||
|
echo "\$0 \$@" >> /var/log/{script}
|
||||||
|
case "\$1 \$2" in'''.format(script=script))
|
||||||
|
for k, v in args.items():
|
||||||
|
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
|
||||||
6
test/requirements.txt
Normal file
6
test/requirements.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
docker-compose
|
||||||
|
pytest
|
||||||
|
pytest-xdist
|
||||||
|
pytest-cov
|
||||||
|
pytest-testinfra
|
||||||
|
tox
|
||||||
6
test/setup.py
Normal file
6
test/setup.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
setup(
|
||||||
|
setup_requires=['pytest-runner'],
|
||||||
|
tests_require=['pytest'],
|
||||||
|
)
|
||||||
1154
test/test_automated_install.py
Normal file
1154
test/test_automated_install.py
Normal file
File diff suppressed because it is too large
Load Diff
63
test/test_centos_7_support.py
Normal file
63
test/test_centos_7_support.py
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
from .conftest import (
|
||||||
|
tick_box,
|
||||||
|
info_box,
|
||||||
|
mock_command,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_php_upgrade_default_optout_centos_eq_7(host):
|
||||||
|
'''
|
||||||
|
confirms the default behavior to opt-out of installing PHP7 from REMI
|
||||||
|
'''
|
||||||
|
package_manager_detect = host.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
package_manager_detect
|
||||||
|
select_rpm_php
|
||||||
|
''')
|
||||||
|
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||||
|
'Deprecated PHP may be in use.')
|
||||||
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
|
remi_package = host.package('remi-release')
|
||||||
|
assert not remi_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
|
def test_php_upgrade_user_optout_centos_eq_7(host):
|
||||||
|
'''
|
||||||
|
confirms installer behavior when user opt-out of installing PHP7 from REMI
|
||||||
|
(php not currently installed)
|
||||||
|
'''
|
||||||
|
# Whiptail dialog returns Cancel for user prompt
|
||||||
|
mock_command('whiptail', {'*': ('', '1')}, host)
|
||||||
|
package_manager_detect = host.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
package_manager_detect
|
||||||
|
select_rpm_php
|
||||||
|
''')
|
||||||
|
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||||
|
'Deprecated PHP may be in use.')
|
||||||
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
|
remi_package = host.package('remi-release')
|
||||||
|
assert not remi_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
|
def test_php_upgrade_user_optin_centos_eq_7(host):
|
||||||
|
'''
|
||||||
|
confirms installer behavior when user opt-in to installing PHP7 from REMI
|
||||||
|
(php not currently installed)
|
||||||
|
'''
|
||||||
|
# Whiptail dialog returns Continue for user prompt
|
||||||
|
mock_command('whiptail', {'*': ('', '0')}, host)
|
||||||
|
package_manager_detect = host.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
package_manager_detect
|
||||||
|
select_rpm_php
|
||||||
|
''')
|
||||||
|
assert 'opt-out' not in package_manager_detect.stdout
|
||||||
|
expected_stdout = info_box + (' Enabling Remi\'s RPM repository '
|
||||||
|
'(https://rpms.remirepo.net)')
|
||||||
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
|
expected_stdout = tick_box + (' Remi\'s RPM repository has '
|
||||||
|
'been enabled for PHP7')
|
||||||
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
|
remi_package = host.package('remi-release')
|
||||||
|
assert remi_package.is_installed
|
||||||
68
test/test_centos_8_support.py
Normal file
68
test/test_centos_8_support.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
from .conftest import (
|
||||||
|
tick_box,
|
||||||
|
info_box,
|
||||||
|
mock_command,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_php_upgrade_default_continue_centos_gte_8(host):
|
||||||
|
'''
|
||||||
|
confirms the latest version of CentOS continues / does not optout
|
||||||
|
(should trigger on CentOS7 only)
|
||||||
|
'''
|
||||||
|
package_manager_detect = host.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
package_manager_detect
|
||||||
|
select_rpm_php
|
||||||
|
''')
|
||||||
|
unexpected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS.'
|
||||||
|
' Deprecated PHP may be in use.')
|
||||||
|
assert unexpected_stdout not in package_manager_detect.stdout
|
||||||
|
# ensure remi was not installed on latest CentOS
|
||||||
|
remi_package = host.package('remi-release')
|
||||||
|
assert not remi_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
|
def test_php_upgrade_user_optout_skipped_centos_gte_8(host):
|
||||||
|
'''
|
||||||
|
confirms installer skips user opt-out of installing PHP7 from REMI on
|
||||||
|
latest CentOS (should trigger on CentOS7 only)
|
||||||
|
(php not currently installed)
|
||||||
|
'''
|
||||||
|
# Whiptail dialog returns Cancel for user prompt
|
||||||
|
mock_command('whiptail', {'*': ('', '1')}, host)
|
||||||
|
package_manager_detect = host.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
package_manager_detect
|
||||||
|
select_rpm_php
|
||||||
|
''')
|
||||||
|
unexpected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS.'
|
||||||
|
' Deprecated PHP may be in use.')
|
||||||
|
assert unexpected_stdout not in package_manager_detect.stdout
|
||||||
|
# ensure remi was not installed on latest CentOS
|
||||||
|
remi_package = host.package('remi-release')
|
||||||
|
assert not remi_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
|
def test_php_upgrade_user_optin_skipped_centos_gte_8(host):
|
||||||
|
'''
|
||||||
|
confirms installer skips user opt-in to installing PHP7 from REMI on
|
||||||
|
latest CentOS (should trigger on CentOS7 only)
|
||||||
|
(php not currently installed)
|
||||||
|
'''
|
||||||
|
# Whiptail dialog returns Continue for user prompt
|
||||||
|
mock_command('whiptail', {'*': ('', '0')}, host)
|
||||||
|
package_manager_detect = host.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
package_manager_detect
|
||||||
|
select_rpm_php
|
||||||
|
''')
|
||||||
|
assert 'opt-out' not in package_manager_detect.stdout
|
||||||
|
unexpected_stdout = info_box + (' Enabling Remi\'s RPM repository '
|
||||||
|
'(https://rpms.remirepo.net)')
|
||||||
|
assert unexpected_stdout not in package_manager_detect.stdout
|
||||||
|
unexpected_stdout = tick_box + (' Remi\'s RPM repository has '
|
||||||
|
'been enabled for PHP7')
|
||||||
|
assert unexpected_stdout not in package_manager_detect.stdout
|
||||||
|
remi_package = host.package('remi-release')
|
||||||
|
assert not remi_package.is_installed
|
||||||
125
test/test_centos_common_support.py
Normal file
125
test/test_centos_common_support.py
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
import pytest
|
||||||
|
from .conftest import (
|
||||||
|
tick_box,
|
||||||
|
info_box,
|
||||||
|
cross_box,
|
||||||
|
mock_command,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_release_supported_version_check_centos(host):
|
||||||
|
'''
|
||||||
|
confirms installer exits on unsupported releases of CentOS
|
||||||
|
'''
|
||||||
|
# modify /etc/redhat-release to mock an unsupported CentOS release
|
||||||
|
host.run('echo "CentOS Linux release 6.9" > /etc/redhat-release')
|
||||||
|
package_manager_detect = host.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
package_manager_detect
|
||||||
|
select_rpm_php
|
||||||
|
''')
|
||||||
|
expected_stdout = cross_box + (' CentOS 6 is not supported.')
|
||||||
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
|
expected_stdout = 'Please update to CentOS release 7 or later'
|
||||||
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
|
|
||||||
|
|
||||||
|
def test_enable_epel_repository_centos(host):
|
||||||
|
'''
|
||||||
|
confirms the EPEL package repository is enabled when installed on CentOS
|
||||||
|
'''
|
||||||
|
package_manager_detect = host.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
package_manager_detect
|
||||||
|
select_rpm_php
|
||||||
|
''')
|
||||||
|
expected_stdout = info_box + (' Enabling EPEL package repository '
|
||||||
|
'(https://fedoraproject.org/wiki/EPEL)')
|
||||||
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
|
expected_stdout = tick_box + ' Installed epel-release'
|
||||||
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
|
epel_package = host.package('epel-release')
|
||||||
|
assert epel_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
|
def test_php_version_lt_7_detected_upgrade_default_optout_centos(host):
|
||||||
|
'''
|
||||||
|
confirms the default behavior to opt-out of upgrading to PHP7 from REMI
|
||||||
|
'''
|
||||||
|
# first we will install the default php version to test installer behavior
|
||||||
|
php_install = host.run('yum install -y php')
|
||||||
|
assert php_install.rc == 0
|
||||||
|
php_package = host.package('php')
|
||||||
|
default_centos_php_version = php_package.version.split('.')[0]
|
||||||
|
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
||||||
|
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
||||||
|
package_manager_detect = host.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
package_manager_detect
|
||||||
|
select_rpm_php
|
||||||
|
''')
|
||||||
|
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||||
|
'Deprecated PHP may be in use.')
|
||||||
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
|
remi_package = host.package('remi-release')
|
||||||
|
assert not remi_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
|
def test_php_version_lt_7_detected_upgrade_user_optout_centos(host):
|
||||||
|
'''
|
||||||
|
confirms installer behavior when user opt-out to upgrade to PHP7 via REMI
|
||||||
|
'''
|
||||||
|
# first we will install the default php version to test installer behavior
|
||||||
|
php_install = host.run('yum install -y php')
|
||||||
|
assert php_install.rc == 0
|
||||||
|
php_package = host.package('php')
|
||||||
|
default_centos_php_version = php_package.version.split('.')[0]
|
||||||
|
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
||||||
|
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
||||||
|
# Whiptail dialog returns Cancel for user prompt
|
||||||
|
mock_command('whiptail', {'*': ('', '1')}, host)
|
||||||
|
package_manager_detect = host.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
package_manager_detect
|
||||||
|
select_rpm_php
|
||||||
|
''')
|
||||||
|
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||||
|
'Deprecated PHP may be in use.')
|
||||||
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
|
remi_package = host.package('remi-release')
|
||||||
|
assert not remi_package.is_installed
|
||||||
|
|
||||||
|
|
||||||
|
def test_php_version_lt_7_detected_upgrade_user_optin_centos(host):
|
||||||
|
'''
|
||||||
|
confirms installer behavior when user opt-in to upgrade to PHP7 via REMI
|
||||||
|
'''
|
||||||
|
# first we will install the default php version to test installer behavior
|
||||||
|
php_install = host.run('yum install -y php')
|
||||||
|
assert php_install.rc == 0
|
||||||
|
php_package = host.package('php')
|
||||||
|
default_centos_php_version = php_package.version.split('.')[0]
|
||||||
|
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
||||||
|
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
||||||
|
# Whiptail dialog returns Continue for user prompt
|
||||||
|
mock_command('whiptail', {'*': ('', '0')}, host)
|
||||||
|
package_manager_detect = host.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
package_manager_detect
|
||||||
|
select_rpm_php
|
||||||
|
install_dependent_packages PIHOLE_WEB_DEPS[@]
|
||||||
|
''')
|
||||||
|
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||||
|
'Deprecated PHP may be in use.')
|
||||||
|
assert expected_stdout not in package_manager_detect.stdout
|
||||||
|
expected_stdout = info_box + (' Enabling Remi\'s RPM repository '
|
||||||
|
'(https://rpms.remirepo.net)')
|
||||||
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
|
expected_stdout = tick_box + (' Remi\'s RPM repository has '
|
||||||
|
'been enabled for PHP7')
|
||||||
|
assert expected_stdout in package_manager_detect.stdout
|
||||||
|
remi_package = host.package('remi-release')
|
||||||
|
assert remi_package.is_installed
|
||||||
|
updated_php_package = host.package('php')
|
||||||
|
updated_php_version = updated_php_package.version.split('.')[0]
|
||||||
|
assert int(updated_php_version) == 7
|
||||||
65
test/test_centos_fedora_common_support.py
Normal file
65
test/test_centos_fedora_common_support.py
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
from .conftest import (
|
||||||
|
tick_box,
|
||||||
|
cross_box,
|
||||||
|
mock_command,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def mock_selinux_config(state, host):
|
||||||
|
'''
|
||||||
|
Creates a mock SELinux config file with expected content
|
||||||
|
'''
|
||||||
|
# validate state string
|
||||||
|
valid_states = ['enforcing', 'permissive', 'disabled']
|
||||||
|
assert state in valid_states
|
||||||
|
# getenforce returns the running state of SELinux
|
||||||
|
mock_command('getenforce', {'*': (state.capitalize(), '0')}, host)
|
||||||
|
# create mock configuration with desired content
|
||||||
|
host.run('''
|
||||||
|
mkdir /etc/selinux
|
||||||
|
echo "SELINUX={state}" > /etc/selinux/config
|
||||||
|
'''.format(state=state.lower()))
|
||||||
|
|
||||||
|
|
||||||
|
def test_selinux_enforcing_exit(host):
|
||||||
|
'''
|
||||||
|
confirms installer prompts to exit when SELinux is Enforcing by default
|
||||||
|
'''
|
||||||
|
mock_selinux_config("enforcing", host)
|
||||||
|
check_selinux = host.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
checkSelinux
|
||||||
|
''')
|
||||||
|
expected_stdout = cross_box + ' Current SELinux: Enforcing'
|
||||||
|
assert expected_stdout in check_selinux.stdout
|
||||||
|
expected_stdout = 'SELinux Enforcing detected, exiting installer'
|
||||||
|
assert expected_stdout in check_selinux.stdout
|
||||||
|
assert check_selinux.rc == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_selinux_permissive(host):
|
||||||
|
'''
|
||||||
|
confirms installer continues when SELinux is Permissive
|
||||||
|
'''
|
||||||
|
mock_selinux_config("permissive", host)
|
||||||
|
check_selinux = host.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
checkSelinux
|
||||||
|
''')
|
||||||
|
expected_stdout = tick_box + ' Current SELinux: Permissive'
|
||||||
|
assert expected_stdout in check_selinux.stdout
|
||||||
|
assert check_selinux.rc == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_selinux_disabled(host):
|
||||||
|
'''
|
||||||
|
confirms installer continues when SELinux is Disabled
|
||||||
|
'''
|
||||||
|
mock_selinux_config("disabled", host)
|
||||||
|
check_selinux = host.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
checkSelinux
|
||||||
|
''')
|
||||||
|
expected_stdout = tick_box + ' Current SELinux: Disabled'
|
||||||
|
assert expected_stdout in check_selinux.stdout
|
||||||
|
assert check_selinux.rc == 0
|
||||||
16
test/test_fedora_support.py
Normal file
16
test/test_fedora_support.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
def test_epel_and_remi_not_installed_fedora(host):
|
||||||
|
'''
|
||||||
|
confirms installer does not attempt to install EPEL/REMI repositories
|
||||||
|
on Fedora
|
||||||
|
'''
|
||||||
|
package_manager_detect = host.run('''
|
||||||
|
source /opt/pihole/basic-install.sh
|
||||||
|
package_manager_detect
|
||||||
|
select_rpm_php
|
||||||
|
''')
|
||||||
|
assert package_manager_detect.stdout == ''
|
||||||
|
|
||||||
|
epel_package = host.package('epel-release')
|
||||||
|
assert not epel_package.is_installed
|
||||||
|
remi_package = host.package('remi-release')
|
||||||
|
assert not remi_package.is_installed
|
||||||
8
test/tox.centos_7.ini
Normal file
8
test/tox.centos_7.ini
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[tox]
|
||||||
|
envlist = py38
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
whitelist_externals = docker
|
||||||
|
deps = -rrequirements.txt
|
||||||
|
commands = docker build -f _centos_7.Dockerfile -t pytest_pihole:test_container ../
|
||||||
|
pytest {posargs:-vv -n auto} ./test_automated_install.py ./test_centos_fedora_common_support.py ./test_centos_common_support.py ./test_centos_7_support.py
|
||||||
8
test/tox.centos_8.ini
Normal file
8
test/tox.centos_8.ini
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[tox]
|
||||||
|
envlist = py38
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
whitelist_externals = docker
|
||||||
|
deps = -rrequirements.txt
|
||||||
|
commands = docker build -f _centos_8.Dockerfile -t pytest_pihole:test_container ../
|
||||||
|
pytest {posargs:-vv -n auto} ./test_automated_install.py ./test_centos_fedora_common_support.py ./test_centos_common_support.py ./test_centos_8_support.py
|
||||||
8
test/tox.debian_10.ini
Normal file
8
test/tox.debian_10.ini
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[tox]
|
||||||
|
envlist = py38
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
whitelist_externals = docker
|
||||||
|
deps = -rrequirements.txt
|
||||||
|
commands = docker build -f _debian_10.Dockerfile -t pytest_pihole:test_container ../
|
||||||
|
pytest {posargs:-vv -n auto} ./test_automated_install.py
|
||||||
8
test/tox.debian_11.ini
Normal file
8
test/tox.debian_11.ini
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[tox]
|
||||||
|
envlist = py38
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
whitelist_externals = docker
|
||||||
|
deps = -rrequirements.txt
|
||||||
|
commands = docker build -f _debian_11.Dockerfile -t pytest_pihole:test_container ../
|
||||||
|
pytest {posargs:-vv -n auto} ./test_automated_install.py
|
||||||
8
test/tox.debian_9.ini
Normal file
8
test/tox.debian_9.ini
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[tox]
|
||||||
|
envlist = py38
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
whitelist_externals = docker
|
||||||
|
deps = -rrequirements.txt
|
||||||
|
commands = docker build -f _debian_9.Dockerfile -t pytest_pihole:test_container ../
|
||||||
|
pytest {posargs:-vv -n auto} ./test_automated_install.py
|
||||||
8
test/tox.fedora_33.ini
Normal file
8
test/tox.fedora_33.ini
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[tox]
|
||||||
|
envlist = py38
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
whitelist_externals = docker
|
||||||
|
deps = -rrequirements.txt
|
||||||
|
commands = docker build -f _fedora_33.Dockerfile -t pytest_pihole:test_container ../
|
||||||
|
pytest {posargs:-vv -n auto} ./test_automated_install.py ./test_centos_fedora_common_support.py ./test_fedora_support.py
|
||||||
8
test/tox.fedora_34.ini
Normal file
8
test/tox.fedora_34.ini
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[tox]
|
||||||
|
envlist = py38
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
whitelist_externals = docker
|
||||||
|
deps = -rrequirements.txt
|
||||||
|
commands = docker build -f _fedora_34.Dockerfile -t pytest_pihole:test_container ../
|
||||||
|
pytest {posargs:-vv -n auto} ./test_automated_install.py ./test_centos_fedora_common_support.py ./test_fedora_support.py
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user