Skip to content

Commit a4a523c

Browse files
committed
Initial project commit
0 parents  commit a4a523c

File tree

9 files changed

+345
-0
lines changed

9 files changed

+345
-0
lines changed

.gitignore

Whitespace-only changes.

LICENSE.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Simplified BSD License
2+
3+
Copyright (c) 2023 Jeffrey Carpenter <1329364+i8degrees@users.noreply.github.com>
4+
All rights reserved.
5+
6+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
7+
8+
1. Redistributions of source code must retain the above copyright notice, this
9+
list of conditions and the following disclaimer.
10+
2. Redistributions in binary form must reproduce the above copyright notice,
11+
this list of conditions and the following disclaimer in the documentation
12+
and/or other materials provided with the distribution.
13+
14+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# pihole_sync
2+
3+
This is a simple workaround script I have come up with in order to maintain a
4+
secondary DNS server while using Pi-Hole as my primary DNS resolver --
5+
although, ad-blocking functionality is lost when the primary goes down, internal
6+
host resolving remains and therefore the critical functionality I need is
7+
preserved.
8+
9+
It was not feasible for me to maintain a block-list on the RAM-starved router
10+
box I am using this script on -- I've tried! Oh well.
11+
12+
## Target
13+
14+
OpenWrt 22.03.3 r20028-43d71ad93e
15+
16+
## Installation
17+
18+
From within the root directory of this project repository...
19+
20+
```shell
21+
# Install dependencies; we need scp from the package...
22+
opkg install openssh-client-utils
23+
mkdir -p /root/bin
24+
cp -av bin/pihole_sync.sh /root/bin/pihole_sync.sh
25+
cp -av etc/init.d/pihole /etc/init.d/pihole
26+
# rc.d run-level scripts have yet to be written, so no enable syntax like we
27+
# have with other services -- so you must start the daemon manually upon boot
28+
cat etc/rc.local >> /etc/rc.local
29+
# Sync every five minutes is the default
30+
cp -av cron/crontab /var/spool/cron/crontabs/root
31+
/etc/init.d/cron enable
32+
/etc/init.d/cron start
33+
```
34+
35+
You must modify the **sync** function in `/root/bin/pihole_sync.sh` if you
36+
expect this to work on your network; change the path of the source configuration
37+
files.
38+
39+
## usage
40+
41+
```shell
42+
# SSH user and host of the pihole box to sync
43+
/root/bin/pihole_sync.sh user@domain.tld
44+
```
45+
46+
**NOTE:** I have not tested this script with non-superuser accounts. I do not
47+
expect it to work out of the box! It should be simple to add, though, as
48+
the `dnsmasq` daemon is ran under a *user* account, not `root`.

TODO.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# TODO
2+
3+
- [ ] Create a Debian package file
4+
- [ ] Write rc.d init scripts for `bin/pihole_sync.sh`
5+
* Base off of `/etc/rc.d/S19dnsmasq`
6+
* **OpenWrt v22.03.3** *r20028-43d71ad93e*
7+
- [ ] Install script
8+

bin/pihole_sync.sh

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#!/usr/bin/env ash
2+
#
3+
# /root/dns_sync.sh:jeff
4+
#
5+
# Sync ns1.lan dnsmasq configuration and suit it for running a backup NS on this box
6+
# for redundancy sake. We lose adblocking in doing so like this, but we maintain the
7+
# crucial internal LAN hostname mappings.
8+
#
9+
# TODO(jeff): Consider using a dedicated user account for sync?
10+
#
11+
12+
PATH="/bin:/sbin:/usr/bin:/usr/sbin"
13+
14+
PING_BIN="$(command -v ping)"
15+
# Internal variables used in the sync function.
16+
SCP_BIN="$(command -v scp)"
17+
18+
# Sanity check of the existence of a given path (executable).
19+
check_app_path() {
20+
APP="$1"
21+
if [ ! -x "$APP" ]; then
22+
echo "CRITICAL: Could not find ${APP} or it is non-executable."
23+
echo
24+
exit 2
25+
fi
26+
}
27+
28+
# Sanity check of the existence of a host.
29+
#
30+
# check_ip4_host(addr)
31+
# ...where addr is an IPv4 address or a hostname that is
32+
# resolvable by DNS.
33+
check_ip4_host() {
34+
ADDR="$1"
35+
if [ ! $("$PING_BIN" -4 -w5 "$ADDR") ]; then
36+
echo "CRITICAL: Could not reach the host at ${ADDR}."
37+
echo
38+
exit 254
39+
fi
40+
}
41+
42+
# Perform allocation duties of target directory paths and
43+
# logging files.
44+
setup() {
45+
mkdir -p "/etc/pihole"
46+
mkdir -p "/etc/dnsmasq.d"
47+
mkdir -p "/var/log/pihole"
48+
touch "/var/log/pihole/pihole.log"
49+
touch "/etc/pihole/dnsmasq.conf"
50+
51+
# IMPORTANT(jeff): This matches /etc/dnsmasq.conf on the virtual Pihole box that
52+
# we do not have SSH access to, less and except the username swap from pihole
53+
# to dnsmasq.
54+
if [ ! $(grep -i -e "conf-dir=/etc/dnsmasq.d" /etc/pihole/dnsmasq.conf) ]; then
55+
echo -e "conf-dir=/etc/dnsmasq.d" >> "/etc/pihole/dnsmasq.conf"
56+
fi
57+
58+
if [ ! $(grep -i -e "user=dnsmasq" /etc/pihole/dnsmasq.conf) ]; then
59+
echo -e "user=dnsmasq\n" >> "/etc/pihole/dnsmasq.conf"
60+
fi
61+
}
62+
63+
# Synchronize the local authoritative nameserver to then host as a backup
64+
# nameserver for the host resolution of local hosts.
65+
#
66+
# sync(ssh_source_host)
67+
# ...where ssh_source_host is a string containing the username and host of the
68+
# SSH target whose files we are copying from.
69+
sync() {
70+
SCP_ARGS="-O" # openwrt compat
71+
SOURCE="$1"
72+
SOURCE_CONFIG_PATH="/mnt/npool0/software/Applications/pihole-1/config"
73+
SOURCE_DNSMASQ_PATH="/mnt/npool0/software/Applications/pihole-1/mounts/dnsmasq"
74+
TARGET_CONFIG_PATH="/etc/pihole"
75+
TARGET_DNSMASQ_PATH="/etc/dnsmasq.d"
76+
77+
if [ -z "${SOURCE}" ]; then
78+
echo "CRITICAL: Missing function parameter in sync function -- ssh source host."
79+
echo
80+
exit 253
81+
fi
82+
83+
# TO /etc/pihole
84+
"${SCP_BIN}" "${SCP_ARGS}" "${SOURCE}:${SOURCE_CONFIG_PATH}/local.list" "${TARGET_CONFIG_PATH}/local.list"
85+
"${SCP_BIN}" "${SCP_ARGS}" "${SOURCE}:${SOURCE_CONFIG_PATH}/custom.list" "${TARGET_CONFIG_PATH}/custom.list"
86+
#"${SCP_BIN}" "${SCP_ARGS}" "${SOURCE}:${SOURCE_CONFIG_PATH}/hosts" "${TARGET_CONFIG_PATH}/hosts"
87+
88+
# TO /etc/dnsmasq.d
89+
"$SCP_BIN" "$SCP_ARGS" "${SOURCE}:${SOURCE_DNSMASQ_PATH}/01-pihole.conf" "${TARGET_DNSMASQ_PATH}/01-pihole.conf"
90+
"$SCP_BIN" "$SCP_ARGS" "${SOURCE}:${SOURCE_DNSMASQ_PATH}/05-pihole-custom-cname.conf" "${TARGET_DNSMASQ_PATH}/05-pihole-custom-cname.conf"
91+
"$SCP_BIN" "$SCP_ARGS" "${SOURCE}:${SOURCE_DNSMASQ_PATH}/06-rfc6761.conf" "${TARGET_DNSMASQ_PATH}/06-rfc6761.conf"
92+
"$SCP_BIN" "$SCP_ARGS" "${SOURCE}:${SOURCE_DNSMASQ_PATH}/99-extra.conf" "${TARGET_DNSMASQ_PATH}/99-extra.conf"
93+
}
94+
95+
# The source configuration files must be modified before usage on another host.
96+
# This function strives to perform the most minimal changes necessary for working
97+
# functionality as a backup nameserver.
98+
#
99+
# adjust_config(boolean)
100+
# ...where boolean is an optional parameter whose non-nil value will abort performing
101+
# any adjustments, giving one the raw configuration as was seen on the source.
102+
adjust_config() {
103+
NOM_SYNC_RAW="$1"
104+
if [ "$NOM_FIX_CONFIG" = "true" ] || [ "$NOM_FIX_CONFIG" = "1" ]; then
105+
if [ ! $(grep -i -e "interface=br-lan" /etc/dnsmasq.d/01-pihole.conf) ]; then
106+
echo "interface=br-lan" >> /etc/dnsmasq.d/01-pihole.conf
107+
sed -i 's/^rev-server=/#&/' /etc/dnsmasq.d/01-pihole.conf
108+
#echo "addn-hosts=/etc/pihole/hosts\n" >> /etc/dnsmasq.d/01-pihole.conf
109+
fi
110+
else
111+
if [ -n "$NOM_DEBUG" ]; then
112+
echo "DEBUG: Not adjusting the source configuration -- this is likely to"
113+
echo "break things!"
114+
fi
115+
fi
116+
}
117+
118+
# Final function call; wrap things up before this is called!
119+
on_finish() {
120+
/etc/init.d/pihole reload
121+
}
122+
123+
# Begin main execution...
124+
125+
SOURCE_SSH="$1"
126+
127+
if [[ -z "$SOURCE_SSH" ]]; then
128+
echo "CRITICAL: Missing function argument -- a SSH host we may obtain the "
129+
echo "primary configuration files from."
130+
echo
131+
exit 2
132+
fi
133+
134+
check_app_path "${SCP_BIN}"
135+
check_app_path "${PING_BIN}"
136+
#check_ip4_host "${SOURCE_SSH_HOST}"
137+
setup
138+
139+
echo "Opening a connection to... ${SOURCE_SSH}"
140+
sync "$SOURCE_SSH"
141+
142+
adjust_config "true"
143+
on_finish
144+
145+
exit 0
146+
147+
# End main execution...
148+

cron/crontab

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# 1. https://openwrt.org/docs/guide-user/base-system/cron
2+
# 2. https://crontab.guru
3+
4+
SHELL=/bin/ash
5+
MAILFROM=root
6+
MAILTO=i8degrees@gmail.com
7+
CRON_TZ=America/Chicago
8+
9+
# Sync every 5 minutes
10+
5/60 * * * * /root/bin/pihole_sync.sh admin@ns1.lan >> /var/log/pihole_sync.log 2>&1
11+

debian/debian.package

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/root/bin/pihole_sync.sh
2+
/etc/init.d/pihole
3+
/etc/dnsmasq.d
4+
/etc/pihole
5+
/var/log/pihole

etc/init.d/pihole

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#!/usr/bin/env ash
2+
#
3+
# /etc/init.d/pihole:jeff
4+
#
5+
6+
function usage_info() {
7+
SCR_NAME=$(basename)
8+
echo "Syntax: /etc/init.d/${SCR_NAME} [command]"
9+
echo
10+
echo -e "Available commands:"
11+
echo -e "\tstart\t\tStart the service"
12+
echo -e "\tstop\t\tStop the service"
13+
echo -e "\trestart\t\tRestart the service"
14+
echo -e "\treload\t\tReload configuration files (or restart if service does not implement reload)"
15+
echo -e "\tenable\t\tEnable service autostart"
16+
echo -e "\tdisable\t\tDisable service autostart"
17+
echo -e "\tenabled\t\tCheck if service is started on boot"
18+
echo -e "\trunning\t\tCheck if service is running"
19+
echo -e "\tstatus\t\tService status"
20+
echo -e "\ttrace\t\tStart with syscall trace"
21+
echo -e "\tinfo\t\tDump procd service info"
22+
}
23+
24+
function service_status() {
25+
DNSMASQ_PID=$(pgrep dnsmasq)
26+
if [[ "$DNSMASQ_PID" != "" ]]; then
27+
echo "running"
28+
else
29+
echo "stopped"
30+
fi
31+
}
32+
33+
function service_running() {
34+
DNSMASQ_PID=$(pgrep dnsmasq)
35+
if [[ "$DNSMASQ_PID" != "" ]]; then
36+
echo "running"
37+
fi
38+
}
39+
40+
# reload configuration of dnsmasq daemon
41+
function service_reload() {
42+
echo "Reloading configuration for dnsmasq..."
43+
DNSMASQ_PID=$(pgrep dnsmasq)
44+
if [[ "$DNSMASQ_PID" != "" ]]; then
45+
kill -s HUP "$DNSMASQ_PID"
46+
fi
47+
}
48+
49+
function _setup() {
50+
[[ -n "$NOM_DEBUG" ]] && echo "Creating log file..."
51+
mkdir -p /var/log/pihole || exit 255
52+
touch /var/log/pihole/pihole.log || exit 255
53+
}
54+
55+
function service_stop() {
56+
echo "Stopping dnsmasq..."
57+
DNSMASQ_PID=$(pgrep dnsmasq)
58+
if [[ "$DNSMASQ_PID" != "" ]]; then
59+
kill -s 15 "$DNSMASQ_PID"
60+
fi
61+
}
62+
63+
function service_restart() {
64+
echo "Restarting dnsmasq..."
65+
service_stop
66+
service_start
67+
}
68+
69+
function service_start() {
70+
echo "Starting dnsmasq..."
71+
_setup
72+
73+
dnsmasq --pid-file=/var/run/pihole.pid --conf-file=/etc/pihole/dnsmasq.conf 2>&1
74+
}
75+
76+
COMMAND=$1
77+
78+
if [[ -z "$COMMAND" ]]; then
79+
usage_info
80+
exit 1
81+
fi
82+
83+
case "$COMMAND" in
84+
start)
85+
service_start
86+
;;
87+
reload)
88+
service_reload
89+
;;
90+
res*|restart*)
91+
service_restart
92+
;;
93+
stop)
94+
service_stop
95+
;;
96+
running)
97+
service_running
98+
;;
99+
status)
100+
service_status
101+
;;
102+
esac
103+
104+
exit 0
105+

etc/rc.local

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/sh
2+
#
3+
4+
/etc/init.d/pihole restart
5+
6+
exit 0

0 commit comments

Comments
 (0)