Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gravity.sh - github.com/pi-hole/pi-hole.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 0dccd77b8c9efc5c4ad301813a3e1381f2c688a3 (plain)
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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
#!/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.
#
# Compiles a list of ad-serving domains by downloading them from multiple sources
#
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.



# Run this script as root or under sudo
echo ":::"

helpFunc() {
	cat << EOM
::: Pull in domains from adlists
:::
::: Usage: pihole -g
:::
::: Options:
:::  -f, --force			Force lists to be downloaded, even if they don't need updating.
:::  -h, --help				Show this help dialog
EOM
	exit 0
}

PIHOLE_COMMAND="/usr/local/bin/pihole"

adListFile=/etc/pihole/adlists.list
adListDefault=/etc/pihole/adlists.default #being deprecated
adListRepoDefault=/etc/.pihole/adlists.default
whitelistScript="${PIHOLE_COMMAND} -w"
whitelistFile=/etc/pihole/whitelist.txt
blacklistFile=/etc/pihole/blacklist.txt
readonly wildcardlist="/etc/dnsmasq.d/03-pihole-wildcard.conf"

#Source the setupVars from install script for the IP
setupVars=/etc/pihole/setupVars.conf
if [[ -f ${setupVars} ]];then
	. /etc/pihole/setupVars.conf
else
	echo "::: WARNING: /etc/pihole/setupVars.conf missing. Possible installation failure."
	echo ":::          Please run 'pihole -r', and choose the 'reconfigure' option to reconfigure."
	exit 1
fi

#Remove the /* from the end of the IPv4addr.
IPV4_ADDRESS=${IPV4_ADDRESS%/*}
IPV6_ADDRESS=${IPV6_ADDRESS}

# Variables for various stages of downloading and formatting the list
basename=pihole
piholeDir=/etc/${basename}
adList=${piholeDir}/gravity.list
localList=${piholeDir}/local.list
justDomainsExtension=domains
matterAndLight=${basename}.0.matterandlight.txt
supernova=${basename}.1.supernova.txt
preEventHorizon=list.preEventHorizon
eventHorizon=${basename}.2.supernova.txt
accretionDisc=${basename}.3.accretionDisc.txt

skipDownload=false

# Warn users still using pihole.conf that it no longer has any effect (I imagine about 2 people use it)
if [[ -r ${piholeDir}/pihole.conf ]]; then
	echo "::: pihole.conf file no longer supported. Over-rides in this file are ignored."
fi

###########################
# collapse - begin formation of pihole
gravity_collapse() {

  #New Logic:
  # Does /etc/pihole/adlists.list exist? If so leave it alone
  #                                      If not, cp /etc/.pihole/adlists.default /etc/pihole/adlists.list
  # Read from adlists.list

  #The following two blocks will sort out any missing adlists in the /etc/pihole directory, and remove legacy adlists.default
  if [ -f ${adListDefault} ] && [ -f ${adListFile} ]; then
    rm ${adListDefault}
  fi

  if [ ! -f ${adListFile} ]; then
    cp ${adListRepoDefault} ${adListFile}
  fi

	echo "::: Neutrino emissions detected..."
	echo ":::"
  echo -n "::: Pulling source lists into range..."
  sources=()
  while IFS= read -r line || [[ -n "$line" ]]; do
    #Do not read commented out or blank lines
    if [[ ${line} = \#* ]] || [[ ! ${line} ]]; then
      echo "" > /dev/null
    else
      sources+=(${line})
    fi
  done < ${adListFile}
  echo " done!"
}

# patternCheck - check to see if curl downloaded any new files.
gravity_patternCheck() {
	patternBuffer=$1
	success=$2
	error=$3
	if [ $success = true ]; then
		# check if download was successful but list has not been modified
		if [ "${error}" == "304" ]; then
			echo ":::   No changes detected, transport skipped!"
		# check if the patternbuffer is a non-zero length file
		elif [[ -s "${patternBuffer}" ]]; then
			# Some of the blocklists are copyright, they need to be downloaded
			# and stored as is. They can be processed for content after they
			# have been saved.
			mv "${patternBuffer}" "${saveLocation}"
			echo ":::   List updated, transport successful!"
		else
			# Empty file -> use previously downloaded list
			echo ":::   Received empty file, using cached one (list not updated!)"
		fi
	else
		# check if cached list exists
		if [[ -r "${saveLocation}" ]]; then
			echo ":::   List download failed, using cached list (list not updated!)"
		else
			echo ":::   Download failed and no cached list available (list will not be considered)"
		fi
	fi
}

# transport - curl the specified url with any needed command extentions
gravity_transport() {
	url=$1
	cmd_ext=$2
	agent=$3

	# tmp file, so we don't have to store the (long!) lists in RAM
	patternBuffer=$(mktemp)
	heisenbergCompensator=""
	if [[ -r ${saveLocation} ]]; then
		# if domain has been saved, add file for date check to only download newer
		heisenbergCompensator="-z ${saveLocation}"
	fi

	# Silently curl url
	err=$(curl -s -L ${cmd_ext} ${heisenbergCompensator} -w %{http_code} -A "${agent}" ${url} -o ${patternBuffer})

	echo " done"
	# Analyze http response
	echo -n ":::   Status: "
	case "$err" in
		"200"  ) echo "Success (OK)"; success=true;;
		"304"  ) echo "Not modified"; success=true;;
		"403"  ) echo "Forbidden"; success=false;;
		"404"  ) echo "Not found"; success=false;;
		"408"  ) echo "Time-out"; success=false;;
		"451"  ) echo "Unavailable For Legal Reasons"; success=false;;
		"521"  ) echo "Web Server Is Down (Cloudflare)"; success=false;;
		"522"  ) echo "Connection Timed Out (Cloudflare)"; success=false;;
		"500"  ) echo "Internal Server Error"; success=false;;
		*      ) echo "Status $err"; success=false;;
	esac

	# Process result
	gravity_patternCheck "${patternBuffer}" ${success} "${err}"
        
        # Delete temp file if it hasn't been moved
        if [[ -f "${patternBuffer}" ]]; then
                rm "${patternBuffer}"
        fi
}

# spinup - main gravity function
gravity_spinup() {
	echo ":::"
	# Loop through domain list.  Download each one and remove commented lines (lines beginning with '# 'or '/') and	 		# blank lines
	for ((i = 0; i < "${#sources[@]}"; i++)); do
		url=${sources[$i]}
		# Get just the domain from the URL
		domain=$(echo "${url}" | cut -d'/' -f3)

		# Save the file as list.#.domain
		saveLocation=${piholeDir}/list.${i}.${domain}.${justDomainsExtension}
		activeDomains[$i]=${saveLocation}

		agent="Mozilla/10.0"

		# Use a case statement to download lists that need special cURL commands
		# to complete properly and reset the user agent when required
		case "${domain}" in
		    "adblock.mahakala.is")
			agent='Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36'
			cmd_ext="-e http://forum.xda-developers.com/"
		    ;;
		    
		    "adaway.org")
			agent='Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36'
		    ;;

		    "pgl.yoyo.org")
			cmd_ext="-d mimetype=plaintext -d hostformat=hosts"
		    ;;

		    # Default is a simple request
		    *) cmd_ext=""
        esac
        if [[ "${skipDownload}" == false ]]; then
            echo -n "::: Getting $domain list..."
            gravity_transport "$url" "$cmd_ext" "$agent"
        fi
	done
}

# Schwarzchild - aggregate domains to one list and add blacklisted domains
gravity_Schwarzchild() {
	echo "::: "
	# Find all active domains and compile them into one file and remove CRs
	echo -n "::: Aggregating list of domains..."
	truncate -s 0 ${piholeDir}/${matterAndLight}
	for i in "${activeDomains[@]}"; do
		# Only assimilate list if it is available (download might have faild permanently)
		if [[ -r "${i}" ]]; then
			cat "${i}" | tr -d '\r' >> ${piholeDir}/${matterAndLight}
		fi
	done
	echo " done!"
}

gravity_Blacklist() {
	# Append blacklist entries to eventHorizon if they exist
	if [[ -f "${blacklistFile}" ]]; then
	    numBlacklisted=$(wc -l < "${blacklistFile}")
	    plural=; [[ "$numBlacklisted" != "1" ]] && plural=s
	    echo -n "::: Blacklisting $numBlacklisted domain${plural}..."
	    cat ${blacklistFile} >> ${piholeDir}/${eventHorizon}
	    echo " done!"
	else
	    echo "::: Nothing to blacklist!"
	fi

}

gravity_Wildcard() {
	# Return number of wildcards in output - don't actually handle wildcards
	if [[ -f "${wildcardlist}" ]]; then
	    numWildcards=$(grep -c ^ "${wildcardlist}")
	    if [[ -n "${IPV4_ADDRESS}" && -n "${IPV6_ADDRESS}" ]];then
	        let numWildcards/=2
	    fi
	    plural=; [[ "$numWildcards" != "1" ]] && plural=s
	    echo "::: Wildcard blocked domain${plural}: $numWildcards"
	else
	    echo "::: No wildcards used!"
	fi

}

gravity_Whitelist() {
    #${piholeDir}/${eventHorizon})
	echo ":::"
	# Prevent our sources from being pulled into the hole
	plural=; [[ "${sources[@]}" != "1" ]] && plural=s
	echo -n "::: Adding adlist source${plural} to the whitelist..."

	urls=()
	for url in "${sources[@]}"; do
		tmp=$(echo "${url}" | awk -F '/' '{print $3}')
		urls=("${urls[@]}" ${tmp})
	done
	echo " done!"

	# Ensure adlist domains are in whitelist.txt
	${whitelistScript} -nr -q "${urls[@]}" > /dev/null

    # Check whitelist.txt exists.
	if [[ -f "${whitelistFile}" ]]; then
        # Remove anything in whitelist.txt from the Event Horizon
        numWhitelisted=$(wc -l < "${whitelistFile}")
        plural=; [[ "$numWhitelisted" != "1" ]] && plural=s
        echo -n "::: Whitelisting $numWhitelisted domain${plural}..."
        #print everything from preEventHorizon into eventHorizon EXCEPT domains in whitelist.txt
        grep -F -x -v -f ${whitelistFile} ${piholeDir}/${preEventHorizon} > ${piholeDir}/${eventHorizon}
        echo " done!"
	else
	    echo "::: Nothing to whitelist!"
	fi
}

gravity_unique() {
	# Sort and remove duplicates
	echo -n "::: Removing duplicate domains...."
	sort -u  ${piholeDir}/${supernova} > ${piholeDir}/${preEventHorizon}
	echo " done!"
	numberOf=$(wc -l < ${piholeDir}/${preEventHorizon})
	echo "::: $numberOf unique domains trapped in the event horizon."
}

gravity_hostFormat() {
	# Format domain list as "192.168.x.x domain.com"
	echo -n "::: Formatting domains into a HOSTS file..."

	if [[ -f /etc/hostname ]]; then
		hostname=$(</etc/hostname)
	elif [ -x "$(command -v hostname)" ]; then
		hostname=$(hostname -f)
	else
		echo "::: Error: Unable to determine fully qualified domain name of host"
	fi
  # Check vars from setupVars.conf to see if we're using IPv4, IPv6, Or both.
  if [[ -n "${IPV4_ADDRESS}" && -n "${IPV6_ADDRESS}" ]];then

      echo -e "${IPV4_ADDRESS} ${hostname}\n${IPV6_ADDRESS} ${hostname}\n${IPV4_ADDRESS} pi.hole\n${IPV6_ADDRESS} pi.hole" > ${localList}
      # Both IPv4 and IPv6
      cat ${piholeDir}/${eventHorizon} | awk -v ipv4addr="$IPV4_ADDRESS" -v ipv6addr="$IPV6_ADDRESS" '{sub(/\r$/,""); print ipv4addr" "$0"\n"ipv6addr" "$0}' >> ${piholeDir}/${accretionDisc}

  elif [[ -n "${IPV4_ADDRESS}" && -z "${IPV6_ADDRESS}" ]];then

      echo -e "${IPV4_ADDRESS} ${hostname}\n${IPV4_ADDRESS} pi.hole" > ${localList}
      # Only IPv4
      cat ${piholeDir}/${eventHorizon} | awk -v ipv4addr="$IPV4_ADDRESS" '{sub(/\r$/,""); print ipv4addr" "$0}' >> ${piholeDir}/${accretionDisc}

  elif [[ -z "${IPV4_ADDRESS}" && -n "${IPV6_ADDRESS}" ]];then

      echo -e "${IPV6_ADDRESS} ${hostname}\n${IPV6_ADDRESS} pi.hole" > ${localList}
      # Only IPv6
      cat ${piholeDir}/${eventHorizon} | awk -v ipv6addr="$IPV6_ADDRESS" '{sub(/\r$/,""); print ipv6addr" "$0}' >> ${piholeDir}/${accretionDisc}

  elif [[ -z "${IPV4_ADDRESS}" && -z "${IPV6_ADDRESS}" ]];then
      echo "::: No IP Values found! Please run 'pihole -r' and choose reconfigure to restore values"
      exit 1
  fi

	# Copy the file over as /etc/pihole/gravity.list so dnsmasq can use it
	cp ${piholeDir}/${accretionDisc} ${adList}
	echo " done!"
}

# blackbody - remove any remnant files from script processes
gravity_blackbody() {
	# Loop through list files
	for file in ${piholeDir}/*.${justDomainsExtension}; do
		# If list is in active array then leave it (noop) else rm the list
		if [[ " ${activeDomains[@]} " =~ ${file} ]]; then
			:
		else
			rm -f "${file}"
		fi
	done
}

gravity_advanced() {
	# Remove comments and print only the domain name
	# Most of the lists downloaded are already in hosts file format but the spacing/formating is not contigious
	# This helps with that and makes it easier to read
	# It also helps with debugging so each stage of the script can be researched more in depth
	echo -n "::: Formatting list of domains to remove comments...."
	#awk '($1 !~ /^#/) { if (NF>1) {print $2} else {print $1}}' ${piholeDir}/${matterAndLight} | sed -nr -e 's/\.{2,}/./g' -e '/\./p' >  ${piholeDir}/${supernova}
	#Above line does not correctly grab domains where comment is on the same line (e.g 'addomain.com #comment')
	#Awk -F splits on given IFS, we grab the right hand side (chops trailing #coments and /'s to grab the domain only.
	#Last awk command takes non-commented lines and if they have 2 fields, take the left field (the domain) and leave
	#+ the right (IP address), otherwise grab the single field.
	cat ${piholeDir}/${matterAndLight} | \
	    awk -F '#' '{print $1}' | \
	    awk -F '/' '{print $1}' | \
	    awk '($1 !~ /^#/) { if (NF>1) {print $2} else {print $1}}' | \
	    sed -nr -e 's/\.{2,}/./g' -e '/\./p' >  ${piholeDir}/${supernova}
	echo " done!"

	numberOf=$(wc -l < ${piholeDir}/${supernova})
	echo "::: ${numberOf} domains being pulled in by gravity..."

	gravity_unique
}

gravity_reload() {
	#Clear no longer needed files...
	echo ":::"
	echo -n "::: Cleaning up un-needed files..."
	rm ${piholeDir}/pihole.*.txt
	echo " done!"

	# Reload hosts file
	echo ":::"
	echo -n "::: Refresh lists in dnsmasq..."

	#ensure /etc/dnsmasq.d/01-pihole.conf is pointing at the correct list!
	#First escape forward slashes in the path:
	adList=${adList//\//\\\/}
	#Now replace the line in dnsmasq file
#	sed -i "s/^addn-hosts.*/addn-hosts=$adList/" /etc/dnsmasq.d/01-pihole.conf

	"${PIHOLE_COMMAND}" restartdns
	echo " done!"
}

for var in "$@"; do
	case "${var}" in
		"-f" | "--force"     ) forceGrav=true;;
		"-h" | "--help"      ) helpFunc;;
		"-sd" | "--skip-download"    ) skipDownload=true;;
	esac
done

if [[ "${forceGrav}" == true ]]; then
	echo -n "::: Deleting exising list cache..."
	rm /etc/pihole/list.*
	echo " done!"
fi

gravity_collapse
gravity_spinup
if [[ "${skipDownload}" == false ]]; then
    gravity_Schwarzchild
    gravity_advanced
else
    echo "::: Using cached Event Horizon list..."
    numberOf=$(wc -l < ${piholeDir}/${preEventHorizon})
	echo "::: $numberOf unique domains trapped in the event horizon."
fi
gravity_Whitelist
gravity_Blacklist
gravity_Wildcard

gravity_hostFormat
gravity_blackbody

gravity_reload
"${PIHOLE_COMMAND}" status