This commit is contained in:
Samuel Aubertin 2023-12-21 15:05:52 +01:00
commit 469b3f09ec
2 changed files with 348 additions and 0 deletions

262
Makefile Normal file
View File

@ -0,0 +1,262 @@
# ██████ ██ ▄█▀▒███████▒ █ █░ ▄████
#▒██ ▒ ██▄█▒ ▒ ▒ ▒ ▄▀░ ▓█░ █ ░█░ ██▒ ▀█▒
#░ ▓██▄ ▓███▄░ ░ ▒ ▄▀▒░ ░█▒░ █ ▒█░ █░█ ▒ ██░▄▄▄░
# ▒ ██▒▓██ █▄ ▄▀▒ ░ ░█░ █ ░█ ░▓█ ██▓
#▒██████▒▒▒██▒ █▄▒███████▒ ░░██▒██▓ ░▒▓███▀▒
#▒ ▒▓▒ ▒ ░▒ ▒▒ ▓▒░▒▒ ▓░▒░▒ ░ ▓░▒ ▒ ░▒ ▒
#░ ░▒ ░ https://git.sk4.nz/sk4nz/skz-wg ░ ░
# ░ ░ ░ ░ ░ ░
.PHONY: clean deps info restart
#.SILENT:
# ░▒▓█ CONFIGURATION █▓▒░
# Change this list to always create clients
# CLIENTS= client1 client2
CLIENTS?=
.poison empty (CLIENTS)
# Install packages, always keep this line before the next block (for curl)
INSTALLPKG!= [ -f .installed ] || (pkg_add -I wireguard-tools libqrencode curl && touch .installed)
# Network configuration
SERVER?!= curl -s ifconfig.co
WG_PORT= 5353
WG_LAN= 10.10.10.1/24
WAN!= route -n show -inet | grep default | awk '{print $$NF}'
# Packet Filter configuration for allowed ports
OUT_TCP= http ftp whois https ssh
IN_TCP= http https ssh
OUT_UDP= domain ntp $(WG_PORT)
IN_UDP= $(WG_PORT)
VPN_TCP= $(IN_TCP)
# Server private key
WG_KEY!= cat server.key 2> /dev/null || wg genkey
.poison empty $(WG_KEY)
# Ads lists
ADS_URLS= https://winhelp2002.mvps.org/hosts.txt
ADS_URLS+= https://pgl.yoyo.org/as/serverlist.php?hostformat=hosts&showintro=0&mimetype=plaintext
ADS_URLS+= https://adaway.org/hosts.txt
ADS_URLS+= https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
# ░▒▓█ TARGETS █▓▒░
all: /etc/pf.wg /var/unbound/etc/unbound.conf
# Enable IPv4 forwarding permanently, if not already
grep forwarding /etc/sysctl.conf 2> /dev/null || (printf 'net.inet.ip.forwarding=1\n' >> /etc/sysctl.conf && sysctl net.inet.ip.forwarding=1)
# Write new pf.conf
grep 'pf.header' /etc/pf.conf || printf 'include "/etc/pf.header"\n' > /etc/pf.conf
grep 'pf.wg' /etc/pf.conf || printf 'include "/etc/pf.wg"\n' >> /etc/pf.conf
# Validate and start new pf.conf
pfctl -nf /etc/pf.conf && pfctl -f /etc/pf.conf
# Restart the WireGuard interface
$(MAKE) restart
$(MAKE) info
restart:
sh /etc/netstart wg0
/etc/pf.bogons:
# Reserved IP addresses to drop, see https://en.wikipedia.org/wiki/Reserved_IP_addresses
printf '0.0.0.0\
\n10.0.0.0/8\
\n100.64.0.0/10\
\n127.0.0.0/8\
\n128.0.0.0/16\
\n169.254.0.0/16\
\n172.16.0.0/12\
\n191.255.0.0/16\
\n192.0.0.0/24\
\n192.0.2.0/24\
\n192.88.99.0/24\
\n192.168.0.0/16\
\n198.18.0.0/15\
\n198.51.100.0/24\
\n203.0.113.0/24\
\n223.255.255.0/24\
\n224.0.0.0/4\
\n240.0.0.0/4\
\n255.255.255.255\n' > $@
/etc/pf.abuse_ssh /etc/pf.abuse_tcp:
# Anti-DDoS persistent tables
touch $@
/etc/pf.header:
# The original pf header
printf 'set skip on lo\nblock return\npass\
\nblock return in on ! lo0 proto tcp to port 6000:6010\
\nblock return out log proto {tcp udp} user _pbuild\n' > $@
/etc/pf.wg: /etc/pf.bogons /etc/pf.abuse_ssh /etc/pf.abuse_tcp /etc/pf.header /etc/pf.conf.orig
# Define allowed PF ports
printf 'out_tcp_ports = "{ $(OUT_TCP) }"\
\nout_udp_ports = "{ $(OUT_UDP) }"\
\nvpn_tcp_ports = "{ $(VPN_TCP) }"\
\nin_tcp_ports = "{ $(IN_TCP) }"\
\nin_udp_ports = "{ $(IN_UDP) }"\n' > $@
# Rules
printf '# BEGIN PF.WG\
\n### Macros \
\n# statefull tracking options - sto\
\n# SSH is considered under abuse when there are more than 6 connections per minute \
\nssh_sto = "(max-src-conn-rate 6/60, overload <t_abuse_ssh> flush global)"\
\n# TCP is considered under abuse when there are more than 300 simultaneous connections or 600 per minute\
\ntcp_sto = "(max-src-conn 300, max-src-conn-rate 600/60, overload <t_abuse_tcp> flush global)"\
\n# TCP flags \
\nflag_syn = "flags S/SA modulate state"\
\n# define e (egress) and i (ingress) macros\
\nedropin = "block drop in quick on egress from"\
\nedropout = "block drop out log quick on egress from"\
\nepassout = "pass out log on egress proto tcp to any port"\
\ninblocktcp = "block in log quick proto tcp from"\
\ninpasstcp = "pass in on egress proto tcp to any port"\
\ninvpntcp = "pass in log on wg0 proto tcp to any port"\
\n# Persitent tables\
\ntable <t_bogons> persist file "/etc/pf.bogons"\
\ntable <t_abuse_tcp> persist file "/etc/pf.abuse_tcp"\
\ntable <t_abuse_ssh> persist file "/etc/pf.abuse_ssh"\
\n# Various security-related options\
\nset block-policy return\
\nset optimization conservative\
\nset reassemble yes\
\nset syncookies adaptive (start 25%%, end 12%%)\
\nset ruleset-optimization profile\
\nset skip on lo\
\nantispoof for { lo, egress }\
\nmatch in all scrub (max-mss 1440 no-df random-id reassemble tcp)\
\n### Rules \
\n# Prevent dns leaks \
\nblock in log on egress inet proto { tcp udp } from any to ! egress port 53\
\n# Block bogons - DEACTIVATED \
\n# TODO : change pf.bogons to allow LAN\
\n#$edropin { <t_bogons> } to any\
\n#$edropout any to { <t_bogons> }\
\n# block abusers\
\n$inblocktcp <t_abuse_ssh> to any port ssh\
\n$inblocktcp <t_abuse_tcp> to any port $in_tcp_ports\
\n# Default rule : block stateless traffic\
\nblock\
\n# Enable ICMP echo request, reply, unreach\
\npass quick inet proto icmp all icmp-type { echoreq, echorep, unreach }\
\n# Enable IPv4 traceroute\
\npass out on egress proto udp to port 33433:33626\
\n# Pass ingress \
\n$inpasstcp ssh $$flag_syn $$ssh_sto\
\n$inpasstcp http $$flag_syn $$tcp_sto\
\n$inpasstcp https $$flag_syn $$tcp_sto\
\n$invpntcp $$vpn_tcp_ports $$flag_syn $$tcp_sto\
\npass in on egress proto udp to any port $$in_udp_ports\
\n# Pass egress\
\n$epassout $$out_tcp_ports $$flag_syn\
\npass out on egress proto udp to any port $$out_udp_ports allow-opts\
\n# Pass Wireguard-LAN\
\npass out log on wg0 proto tcp to any port $$vpn_tcp_ports\
\npass in on wg0 proto udp to any port $$out_udp_ports allow-opts\
\n# END PF.WG\n' >> $@
# NAT the WireGuard interface to WAN
printf 'pass out on $(WAN) inet from wg0:network to any nat-to ($(WAN))' >> $@
ad-blacklist:
rm -rf /var/unbound/ad-blacklist.conf
$(MAKE) /var/unbound/ad-blacklist.conf
/var/unbound/ad-blacklist.conf:
# For the lying DNS resolver
for url in "$(ADS_URLS)"; do curl -s $$url >> /tmp/ads-daily; done
awk -v white='/(api.solvemedia.com)/' '$$1 ~ /^127\.|^0\./ && $$2 !~white {gsub("\r",""); print tolower($$2)}' /tmp/ads-daily | sort | uniq | awk '{printf "server:\n", $$1; printf "local-data: \"%s A 127.0.0.1\"\n", $$1}' > $@
rm -rf /tmp/ads-daily
# Update lists daily
grep 'ad-blacklist' /etc/daily.local || printf 'make -C $(PWD) ad-blacklist\nrcctl restart unbound\n' >> /etc/daily.local
/etc/pf.conf.orig:
# Save original pf.conf
cp /etc/pf.conf $@
/etc/hostname.wg0: server.key $(CLIENTS)
# The WireGuard interface configuration
printf 'wgkey "$(WG_KEY)"\
\nwgport $(WG_PORT)\
\ninet $(WG_LAN)\n' > $@
# Add peers
for cli in $(CLIENTS); do \
N=$$(sha256 -qs $$cli | cut -b 1-2);\
PUB=$$(cat $$cli/$$cli.pub);\
PSK=$$(cat $$cli/$$cli.psk);\
printf "# $$cli\nwgpeer \"$$PUB\" wgpsk \"$$PSK\" wgpka 25 wgaip $(WG_LAN:H:S/.1$/./)"$$(printf $$((0x$$N)))"/32\n" >> $@;\
done
printf 'up\n' >> $@
chmod 640 $@
# Start the wg interface
sh /etc/netstart wg0
/var/unbound/etc/unbound.conf: /etc/hostname.wg0 ad-blacklist
# Unbound configuration, with lying DNS and DNSSEC validation
printf 'server:\
\n\tinterface: 127.0.0.1\
\n\tinterface: $(WG_LAN:H)\
\n\tdo-ip6: no\
\n\taccess-control: 0.0.0.0/0 refuse\
\n\taccess-control: 127.0.0.0/8 allow\
\n\taccess-control: $(WG_LAN) allow\
\n\tauto-trust-anchor-file: "/var/unbound/db/root.key"\
\n\taggressive-nsec: yes\
\n\tinclude: /var/unbound/ad-blacklist.conf\
\n\nremote-control:\
\n\tcontrol-enable: yes\
\n\tcontrol-interface: /var/run/unbound.sock\n' > $@
rcctl enable unbound
rcctl start unbound
info:
printf '\033[1mWireguard: \033[32m$(SERVER):$(WG_PORT) \033[0m$(WG_LAN)\n'
T=$$(wg show all transfer); for cli in $(CLIENTS); do\
N=$$(sha256 -qs $$cli | cut -b 1-2);\
PUB=$$(cat $$cli/$$cli.pub);\
IN=$$(printf "$$T\n" | grep $$PUB | awk '{print $$(NF-1)}');\
OUT=$$(printf "$$T\n" | grep $$PUB | awk '{print $$(NF)}');\
printf '- \033[1m\033[33m%15s\033[0m $(WG_LAN:H:S/.1$/./)%-3s in: %-10s out: '$$OUT'\n' $$cli $$(printf $$((0x$$N))) $$IN;\
done
server.conf: server.pub
# Generate the server configuration header (deprecated)
printf '[Interface] # VOID - Tunnel gateway: $(WG_LAN:H)\n#Address = $(WG_LAN:H)\nListenPort = $(WG_PORT)\nPrivateKey = '$$(cat server.key)'\n' > server.conf;
server.key:
# Generate server private key if not already present
printf $(WG_KEY) > $@
chmod 600 $@
server.pub: server.key
# Generate server pub key if not already present
cat server.key | wg pubkey > $@
chmod 600 $@
$(CLIENTS): server.conf
mkdir -p $@
# Generate priv/pub keys
wg genkey | tee $@/$@.key | wg pubkey > $@/$@.pub
# Generate PSK
touch $@/$@.psk && chmod 600 $@/$@.psk
wg genpsk > $@/$@.psk
# Append to server.conf (deprecated) and the client configuration
PSK=$$(cat $@/$@.psk); PUB=$$(cat $@/$@.pub); N=$$(sha256 -qs $@ | cut -b 1-2);\
echo -e '[Peer] # '$@'\nAllowedIPs = $(WG_LAN:H:S/.1$/./)'$$(echo $$((0x$$N)))'/32\nPublicKey = '$$PUB'\nPresharedKey = '$$PSK'\n' >> server.conf;\
echo -e '[Interface] # Local tunnel address: $(WG_LAN:H:S/.1$/./)'$$(echo $$((0x$$N))) router: $(WG_LAN:H)'\nAddress = $(WG_LAN:H:S/.1$/./)'$$(echo $$((0x$$N)))/32'\nPrivateKey = '$$(cat $@/$@.key)'\nDNS = $(WG_LAN:H)\n[Peer] # Tunnel endpoint: $(SERVER)\nEndpoint = $(SERVER):$(WG_PORT)\nPublicKey = '$$(cat server.pub)'\nPresharedKey = '$$PSK'\nAllowedIPs = 0.0.0.0/0' > $@/$@.conf
cat $@/$@.conf | qrencode -t ansiutf8 -o $@/$@.qr
chmod -R 600 $@
clean:
-ifconfig wg0 down
-rcctl stop unbound
-rcctl disable unbound
-rm -rf $(CLIENTS) *.key *.pub server.conf /var/unblound/ad-blacklist.sh /etc/pf.wg /etc/hostname.wg0 /var/unbound/etc/unbound.conf /etc/pf.header
-sed -i '/ad-blacklist/d' /etc/daily.local
-sed -i '/rcctl restart unbound/d' /etc/daily.local
-cp /etc/pf.conf.orig /etc/pf.conf
pfctl -nf /etc/pf.conf && pfctl -f /etc/pf.conf

86
README.md Normal file
View File

@ -0,0 +1,86 @@
```
██████ ██ ▄█▀▒███████▒ █ █░ ▄████
▒██ ▒ ██▄█▒ ▒ ▒ ▒ ▄▀░ ▓█░ █ ░█░ ██▒ ▀█▒
░ ▓██▄ ▓███▄░ ░ ▒ ▄▀▒░ ░█▒░ █ ▒█░ █░█ ▒ ██░▄▄▄░
▒ ██▒▓██ █▄ ▄▀▒ ░ ░█░ █ ░█ ░▓█ ██▓
▒██████▒▒▒██▒ █▄▒███████▒ ░░██▒██▓ ░▒▓███▀▒
▒ ▒▓▒ ▒ ░▒ ▒▒ ▓▒░▒▒ ▓░▒░▒ ░ ▓░▒ ▒ ░▒ ▒
░ ░▒ ░ https://git.sk4.nz/sk4nz/skz-wg ░ ░
░ ░ ░ ░ ░ ░
```
*Samuel 'sk4nz' AUBERTIN*
**skz-wg** is a VPN (WireGuard) + DNS (Unbound) + Firewall (Packet Filter) automated setup for [OpenBSD](https://www.openbsd.org/) with client configuration management.
**WARNING: The VPN clients _outgoing_ packets are filtered, and the DNS resolver _lies_ for adverting related hosts.**
## Howto
tl;dr: ```make```
### Install, configure and runs WireGuard for client FOO and BAR
```CLIENTS="FOO BAR" make```
### Show informations about the running WireGuard instance
```make info```
## Details
### WireGuard
[WireGuard website](https://www.wireguard.com)
Is configured to listen on ```WG_PORT```, spawning the ```WG_LAN``` private network.
It uses PSK authentication and keep-alives.
#### Server
Optionally declare the server _IP_ address with ```SERVER= IP``` in the _./Makefile_ or using ```SERVER=IP make```.
#### Clients
Declare clients _a_, _b_ and _c_ with ```CLIENTS= a b c``` in the _./Makefile_ or using ```CLIENTS="a b c" make```.
Client management is additive, meaning you can add more with ```CLIENTS="new" make```.
#### Configuration files
Each client has a configuration folder in _./_ named after its name:
```# ls -1 sk4nz/
sk4nz.conf # The client configuration file
sk4nz.key # The client secret key
sk4nz.pub # The client public key
sk4nz.pub # The client PSK
sk4nz.qr # QRcode configuration
```
You can use the ```.conf``` or it's encoded version ```.qr``` to configure clients.
### Unbound
[Unbound website](https://www.nlnetlabs.nl/projects/unbound/)
Lies on ads (used list are declared in ```ADS_URLS```) and validates DNSSEC when available.
### Packet Filter
[OpenBSD PF website](https://www.openbsd.org/faq/pf/)
NATs ```WG_LAN``` and filters both **ingress** _and_ **egress** ports.
To allow more ports, please edit ```IN_TCP```, ```OUT_TCP```, ```IN_UDP```, ```OUT_UDP``` and ```VPN_TCP``` in the _./Makefile_.
#### Ingress: ```IN_TCP```, ```IN_UDP```
- ```IN_TCP```: Allowed ports for the _incoming_ TCP packets _to_ the server WAN interface.
- ```IN_UDP```: Allowed ports for the _incoming_ UDP packets _to_ the server WAN interface.
#### Egress: ```OUT_TCP```, ```OUT_UDP```
- ```OUT_TCP```: Allowed destination ports for the _outgoing_ TCP packets _from_ the server WAN interface.
- ```OUT_UDP```: Allowed destination ports for the _outgoing_ UDP packets _from_ the server WAN interface.
#### NAT: ```VPN_TCP```
Allowed destination ports for packets coming _from_ the ```WG_LAN``` before going throug the NAT.