#!/bin/sh # Version: 3.1.0 # Author: Héctor Molinero Fernández # License: MIT, https://opensource.org/licenses/MIT # Repository: https://github.com/hectorm/hblock set -eu export LC_ALL='C' # Emulate ksh if the shell is zsh. if [ -n "${ZSH_VERSION-}" ]; then emulate -L ksh; fi # Define system and user configuration directories. if [ -z "${ETCDIR+x}" ]; then ETCDIR='/etc'; fi if [ -z "${XDG_CONFIG_HOME+x}" ]; then XDG_CONFIG_HOME="${HOME-}/.config"; fi # Built-in header. HOSTNAME="${HOSTNAME-"$(uname -n)"}" HBLOCK_HEADER_BUILTIN="$(cat <<-EOF 127.0.0.1 localhost ${HOSTNAME?} 255.255.255.255 broadcasthost ::1 localhost ${HOSTNAME?} ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters ff02::3 ip6-allhosts EOF )" # Built-in footer. HBLOCK_FOOTER_BUILTIN='' # Built-in sources. HBLOCK_SOURCES_BUILTIN="$(cat <<-'EOF' https://raw.githubusercontent.com/hectorm/hmirror/master/data/adaway.org/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/adblock-nocoin-list/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/adguard-simplified/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/antipopads/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/digitalside-threat-intel/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/disconnect.me-ad/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/disconnect.me-malvertising/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/disconnect.me-malware/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/disconnect.me-tracking/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/easylist/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/easyprivacy/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/eth-phishing-detect/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/fademind-add.2o7net/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/fademind-add.dead/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/fademind-add.risk/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/fademind-add.spam/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/gfrogeye-firstparty-trackers/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/hostsvn/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/kadhosts/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/lightswitch05-ads-and-tracking/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/malwaredomainlist.com/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/malwaredomains.com-immortaldomains/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/malwaredomains.com-justdomains/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/matomo.org-spammers/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/mitchellkrogza-badd-boyz-hosts/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/pgl.yoyo.org/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/phishing.army/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/socram8888-notonmyshift/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/someonewhocares.org/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/spam404.com/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/stevenblack/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/ublock/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/ublock-abuse/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/ublock-badware/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/ublock-privacy/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/urlhaus/list.txt https://raw.githubusercontent.com/hectorm/hmirror/master/data/winhelp2002.mvps.org/list.txt EOF )" # Built-in allowlist. HBLOCK_ALLOWLIST_BUILTIN='' # Built-in denylist. HBLOCK_DENYLIST_BUILTIN="$(cat <<-'EOF' # Special domain that is used to check if hBlock is enabled. hblock-check.molinero.dev EOF )" # Parse command line options. optParse() { while [ "${#}" -gt '0' ]; do case "${1?}" in # Short options that accept an argument need a "*" in their pattern because they can be # found in the "-A" form. '-O'*|'--output') optArgStr "${@-}"; outputFile="${optArg?}"; shift "${optShift:?}" ;; '-H'*|'--header') optArgStr "${@-}"; headerFile="${optArg?}"; shift "${optShift:?}" ;; '-F'*|'--footer') optArgStr "${@-}"; footerFile="${optArg?}"; shift "${optShift:?}" ;; '-S'*|'--sources') optArgStr "${@-}"; sourcesFile="${optArg?}"; shift "${optShift:?}" ;; '-A'*|'--allowlist') optArgStr "${@-}"; allowlistFile="${optArg?}"; shift "${optShift:?}" ;; '-D'*|'--denylist') optArgStr "${@-}"; denylistFile="${optArg?}"; shift "${optShift:?}" ;; '-R'*|'--redirection') optArgStr "${@-}"; redirection="${optArg?}"; shift "${optShift:?}" ;; '-W'*|'--wrap') optArgStr "${@-}"; wrap="${optArg?}"; shift "${optShift:?}" ;; '-T'*|'--template') optArgStr "${@-}"; template="${optArg?}"; shift "${optShift:?}" ;; '-C'*|'--comment') optArgStr "${@-}"; comment="${optArg?}"; shift "${optShift:?}" ;; '-l' |'--lenient'|'--no-lenient') optArgBool "${@-}"; lenient="${optArg:?}" ;; '-r' |'--regex'|'--no-regex') optArgBool "${@-}"; regex="${optArg:?}" ;; '-c' |'--continue'|'--no-continue') optArgBool "${@-}"; continue="${optArg:?}" ;; '-q' |'--quiet'|'--no-quiet') optArgBool "${@-}"; quiet="${optArg:?}" ;; '-x'*|'--color') optArgStr "${@-}"; color="${optArg?}"; shift "${optShift:?}" ;; '-v' |'--version') showVersion ;; '-h' |'--help') showHelp ;; # If "--" is found, the remaining positional arguments are saved and the parsing ends. --) shift; posArgs="${posArgs-} ${*-}"; break ;; # If a long option in the form "--opt=value" is found, it is split into "--opt" and "value". --*=*) optSplitEquals "${@-}"; shift; set -- "${optName:?}" "${optArg?}" "${@-}"; continue ;; # If an option did not match any pattern, an error is thrown. -?|--*) optDie "Illegal option ${1:?}" ;; # If multiple short options in the form "-AB" are found, they are split into "-A" and "-B". -?*) optSplitShort "${@-}"; shift; set -- "${optAName:?}" "${optBName:?}" "${@-}"; continue ;; # If a positional argument is found, it is saved. *) posArgs="${posArgs-} ${1?}" ;; esac shift done } optSplitShort() { optAName="${1%"${1#??}"}"; optBName="-${1#??}" } optSplitEquals() { optName="${1%="${1#--*=}"}"; optArg="${1#--*=}" } optArgStr() { if [ -n "${1#??}" ] && [ "${1#--}" = "${1:?}" ]; then optArg="${1#??}"; optShift='0'; elif [ -n "${2+x}" ]; then optArg="${2-}"; optShift='1'; else optDie "No argument for ${1:?} option"; fi } optArgBool() { if [ "${1#--no-}" = "${1:?}" ]; then optArg='true'; else optArg='false'; fi } optDie() { printf -- '%s\n' "${@-}" "Try 'hblock --help' for more information" >&2 exit 2 } # Show help and quit. showHelp() { printf -- '%s\n' "$(sed -e 's/%NL/\n/g' <<-EOF Usage: hblock [OPTION]... hBlock is a POSIX-compliant shell script that gets a list of domains that serve ads, tracking scripts and malware from multiple sources and creates a hosts file, among other formats, that prevents your system from connecting to them. Options: -O, --output , \${HBLOCK_OUTPUT_FILE}%NL Output file location.%NL If equals "-", it is printed to stdout.%NL (default: ${outputFile?})%NL -H, --header , \${HBLOCK_HEADER_FILE}%NL File to be included at the beginning of the output file.%NL If equals "builtin", the built-in value is used.%NL If equals "none", an empty value is used.%NL If equals "-", the stdin content is used.%NL If unspecified and any of the following files exists, its content is used.%NL \${XDG_CONFIG_HOME}/hblock/header%NL ${ETCDIR?}/hblock/header%NL (default: ${headerFile?})%NL -F, --footer , \${HBLOCK_FOOTER_FILE}%NL File to be included at the end of the output file.%NL If equals "builtin", the built-in value is used.%NL If equals "none", an empty value is used.%NL If equals "-", the stdin content is used.%NL If unspecified and any of the following files exists, its content is used.%NL \${XDG_CONFIG_HOME}/hblock/footer%NL ${ETCDIR?}/hblock/footer%NL (default: ${footerFile?})%NL -S, --sources , \${HBLOCK_SOURCES_FILE}%NL File with line separated URLs used to generate the blocklist.%NL If equals "builtin", the built-in value is used.%NL If equals "none", an empty value is used.%NL If equals "-", the stdin content is used.%NL If unspecified and any of the following files exists, its content is used.%NL \${XDG_CONFIG_HOME}/hblock/sources.list%NL ${ETCDIR?}/hblock/sources.list%NL (default: ${sourcesFile?})%NL -A, --allowlist , \${HBLOCK_ALLOWLIST_FILE}%NL File with line separated entries to be removed from the blocklist.%NL If equals "builtin", the built-in value is used.%NL If equals "none", an empty value is used.%NL If equals "-", the stdin content is used.%NL If unspecified and any of the following files exists, its content is used.%NL \${XDG_CONFIG_HOME}/hblock/allow.list%NL ${ETCDIR?}/hblock/allow.list%NL (default: ${allowlistFile?})%NL -D, --denylist , \${HBLOCK_DENYLIST_FILE}%NL File with line separated entries to be added to the blocklist.%NL If equals "builtin", the built-in value is used.%NL If equals "none", an empty value is used.%NL If equals "-", the stdin content is used.%NL If unspecified and any of the following files exists, its content is used.%NL \${XDG_CONFIG_HOME}/hblock/deny.list%NL ${ETCDIR?}/hblock/deny.list%NL (default: ${denylistFile?})%NL -R, --redirection , \${HBLOCK_REDIRECTION}%NL Redirection for all entries in the blocklist.%NL (default: ${redirection?})%NL -W, --wrap , \${HBLOCK_WRAP}%NL Break blocklist lines after this number of entries.%NL (default: ${wrap?})%NL -T, --template