-
Notifications
You must be signed in to change notification settings - Fork 173
/
uninstall.py
204 lines (162 loc) · 6.76 KB
/
uninstall.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
import json
import os
import sqlite3
import subprocess
from urllib.request import Request, urlopen
from urllib.error import HTTPError, URLError
def fetch_url(url):
if not url:
return
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0'}
print('[i] Fetching:', url)
try:
response = urlopen(Request(url, headers=headers))
except HTTPError as e:
print('[E] HTTP Error:', e.code, 'whilst fetching', url)
return
except URLError as e:
print('[E] URL Error:', e.reason, 'whilst fetching', url)
return
# Read and decode
response = response.read().decode('UTF-8').replace('\r\n', '\n')
# If there is data
if response:
# Strip leading and trailing whitespace
response = '\n'.join(x for x in map(str.strip, response.splitlines()))
# Return the hosts
return response
url_regexps_remote = 'https://raw.githubusercontent.com/mmotti/pihole-regex/master/regex.list'
install_comment = 'github.com/mmotti/pihole-regex'
cmd_restart = ['pihole', 'restartdns', 'reload']
db_exists = False
conn = None
c = None
regexps_remote = set()
regexps_local = set()
regexps_mmotti_local = set()
regexps_legacy_mmotti = set()
regexps_remove = set()
# Start the docker directory override
print('[i] Checking for "pihole" docker container')
# Initialise the docker variables
docker_id = None
docker_mnt = None
docker_mnt_src = None
# Check to see whether the default "pihole" docker container is active
try:
docker_id = subprocess.run(['docker', 'ps', '--filter', 'name=pihole', '-q'],
stdout=subprocess.PIPE, universal_newlines=True).stdout.strip()
# Exception for if docker is not installed
except FileNotFoundError:
pass
# If a pihole docker container was found, locate the first mount
if docker_id:
docker_mnt = subprocess.run(['docker', 'inspect', '--format', '{{ (json .Mounts) }}', docker_id],
stdout=subprocess.PIPE, universal_newlines=True).stdout.strip()
# Convert output to JSON and iterate through each dict
for json_dict in json.loads(docker_mnt):
# If this mount's destination is /etc/pihole
if json_dict['Destination'] == r'/etc/pihole':
# Use the source path as our target
docker_mnt_src = json_dict['Source']
break
# If we successfully found the mount
if docker_mnt_src:
print('[i] Running in docker installation mode')
# Prepend restart commands
cmd_restart[0:0] = ['docker', 'exec', '-i', 'pihole']
else:
print('[i] Running in physical installation mode ')
# Set paths
path_pihole = docker_mnt_src if docker_mnt_src else r'/etc/pihole'
path_legacy_regex = os.path.join(path_pihole, 'regex.list')
path_legacy_mmotti_regex = os.path.join(path_pihole, 'mmotti-regex.list')
path_pihole_db = os.path.join(path_pihole, 'gravity.db')
# Check that pi-hole path exists
if os.path.exists(path_pihole):
print('[i] Pi-hole path exists')
else:
print(f'[e] {path_pihole} was not found')
exit(1)
# Check for write access to /etc/pihole
if os.access(path_pihole, os.X_OK | os.W_OK):
print(f'[i] Write access to {path_pihole} verified')
else:
print(f'[e] Write access is not available for {path_pihole}. Please run as root or other privileged user')
exit(1)
# Determine whether we are using DB or not
if os.path.isfile(path_pihole_db) and os.path.getsize(path_pihole_db) > 0:
db_exists = True
print('[i] DB detected')
else:
print('[i] Legacy regex.list detected')
# Fetch the remote regexps
str_regexps_remote = fetch_url(url_regexps_remote)
# If regexps were fetched, remove any comments and add to set
if str_regexps_remote:
regexps_remote.update(x for x in map(str.strip, str_regexps_remote.splitlines()) if x and x[:1] != '#')
print(f'[i] {len(regexps_remote)} regexps collected from {url_regexps_remote}')
else:
print('[i] No remote regexps were found.')
exit(1)
if db_exists:
# Create a DB connection
print(f'[i] Connecting to {path_pihole_db}')
try:
conn = sqlite3.connect(path_pihole_db)
except sqlite3.Error as e:
print(e)
exit(1)
# Create a cursor object
c = conn.cursor()
# Identifying mmotti regexps
print("[i] Removing mmotti's regexps")
c.executemany('DELETE FROM domainlist '
'WHERE type = 3 '
'AND (domain in (?) OR comment = ?)',
[(x, install_comment) for x in regexps_remote])
conn.commit()
print('[i] Restarting Pi-hole')
subprocess.run(cmd_restart, stdout=subprocess.DEVNULL)
# Prepare final result
print('[i] Done - Please see your installed regexps below\n')
c.execute('Select domain FROM domainlist WHERE type = 3')
final_results = c.fetchall()
regexps_local.update(x[0] for x in final_results)
print(*sorted(regexps_local), sep='\n')
conn.close()
else:
# If regex.list exists and is not empty
# Read it and add to a set
if os.path.isfile(path_legacy_regex) and os.path.getsize(path_legacy_regex) > 0:
print('[i] Collecting existing entries from regex.list')
with open(path_legacy_regex, 'r') as fRead:
regexps_local.update(x for x in map(str.strip, fRead) if x and x[:1] != '#')
# If the local regexp set is not empty
if regexps_local:
print(f'[i] {len(regexps_local)} existing regexps identified')
# If we have a record of the previous legacy install
if os.path.isfile(path_legacy_mmotti_regex) and os.path.getsize(path_legacy_mmotti_regex) > 0:
print('[i] Existing mmotti-regex install identified')
with open(path_legacy_mmotti_regex, 'r') as fOpen:
regexps_legacy_mmotti.update(x for x in map(str.strip, fOpen) if x and x[:1] != '#')
if regexps_legacy_mmotti:
print(f'[i] Removing regexps found in {path_legacy_mmotti_regex}')
regexps_local.difference_update(regexps_legacy_mmotti)
# Remove mmotti-regex.list as it will no longer be required
os.remove(path_legacy_mmotti_regex)
else:
print('[i] Removing regexps that match the remote repo')
regexps_local.difference_update(regexps_remote)
# Output to regex.list
print(f'[i] Outputting {len(regexps_local)} regexps to {path_legacy_regex}')
with open(path_legacy_regex, 'w') as fWrite:
for line in sorted(regexps_local):
fWrite.write(f'{line}\n')
print('[i] Restarting Pi-hole')
subprocess.run(cmd_restart, stdout=subprocess.DEVNULL)
# Prepare final result
print('[i] Done - Please see your installed regexps below\n')
with open(path_legacy_regex, 'r') as fOpen:
for line in fOpen:
print(line, end='')