commit bf583b98d0ef05b8736ea02165a3a3c41f4d3b2f Author: Ste Vaidis Date: Wed Dec 14 10:24:18 2022 +0200 initial commit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e9d84ae --- /dev/null +++ b/LICENSE @@ -0,0 +1,12 @@ +Copyright (C) 2006 by Rob Landley + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3972a50 --- /dev/null +++ b/README.md @@ -0,0 +1,221 @@ +# Port Forward Opener on OpenBSD + +![Port Forward Opener](./forward_opener.png) + +This setup allow external users to connect to internal servers through port forwarding. + +Usefull for small offices when: + +- You cannot use vpn +- You don't like port knocking + +Let's say a user wants to connect to the server with RDP + +1. The **User** makes a SSH connection to firewall. +2. The Firewall allows for a few seconds the IP of the user to connect to the internal server. +3. The **User** makes a RDP connection to the internal server +3. The Firewall closes SSH connection automatically. + +**It's not ready for production, don't use it if you don't know exactly what you are doing** + +## Addressing Scheme Example + +``` + + [Desktop A] [Desktop B] [Desktop C] + | | | +[DSL]---[Firewall]---[Switch]---+-----+-----+-----+----+ + | | + [Server] [Printer] + + + + Address Node Port Forward + ------------- ------------ ------------------------ + 192.168.1.1 DSL Router + 192.168.1.2 Firewall WAN 22 < 60022 + 192.168.2.1 Firewall LAN + + 192.168.2.11 Desktop A 22 < 60122, 3389 < 63381 + 192.168.2.12 Desktop B 22 < 60222, 3389 < 63382 + 192.168.2.13 Desktop C 22 < 60322, 3389 < 63383 + + 192.168.2.200 Server 3389 < 63389 + 192.168.2.201 Printer + +``` + +## Dependencies + +```bash +pkg_add vim dialog # nothing works properly without vim +``` + +## Network Settings + + +:floppy_disk: `vi /etc/hostname.em0` + +```bash +dhcp +``` + +:floppy_disk: `vi /etc/hostname.stge0` + +```bash +media 100baseTX +mediaopt full-duplex +inet 192.168.2.1 0xffffff00 +``` + +:floppy_disk: `vi /etc/mygate` + +```bash +192.168.1.1 +``` + +:floppy_disk: `vi /etc/resolv.conf` + +```bash +nameserver 9.9.9.9 +nameserver 1.1.1.1 +``` + +## DHCP Server + +:floppy_disk: `vi /etc/dhcpd.conf` + +```bash +option domain-name "taxstudio"; +option domain-name-servers 9.9.9.9; + +subnet 192.168.2.0 netmask 255.255.255.0 { + option routers 192.168.2.1; + range 192.168.2.11 192.168.2.19; +} +``` + +:floppy_disk: `vi /etc/dhcpd.interfaces` + +```bash +stge0 +``` + +Test server `dhcpd -d -c /etc/dhcpd.conf` + +Start DHCP server at boot + +```bash +rcctl set dhcpd flags stge0 +rcctl enable dhcpd +rcctl start dhcpd +``` + +Show leases + +```bash +cat /var/db/dhcpd.lease +``` + + +## Firewall + +Port forwarding + +```bash +sysctl net.inet.ip.forwarding=1 +echo 'net.inet.ip.forwarding=1' >> /etc/sysctl.conf +sysctl | grep ip.forwarding +``` + +Rules + +:floppy_disk: `vi /etc/pf.conf` + +```bash +wan = em0 +lan = stge0 + +#---------------------------------- +# Defaults +#---------------------------------- +pass out keep state + +set skip on lo +set block-policy return +set reassemble yes + +block in all +block return + +match in on $wan scrub (no-df max-mss 1440) +match out on $wan scrub (random-id) + +antispoof quick for { $wan lo0 } + +#---------------------------------- +# Input +#---------------------------------- +pass quick on $lan +pass in quick proto tcp to $wan port 22 keep state +pass in quick on $lan + +#---------------------------------- +# Output +#---------------------------------- +pass out on $lan inet keep state + +#---------------------------------- +# NAT +#---------------------------------- +match out on $wan from !($wan) nat-to ($wan) + +# Allow outgoing traffic for LAN and the gateway +pass out quick keep state +pass in on { $lan } inet +``` + +Enable + +```bash +pfctl -d +pfctl -f /etc/pf.conf +pfctl -e +``` + + +## Setup Opener + +Start at boot and listens the port 3000 + +```bash +echo "/firewall/fw-server.sh" >> /etc/rc.local +``` + +Add Users + +1. Add user to system + +```bash +# fw.sh will executed on user login +useradd -d /dev/null -s /firewall/fw.sh jack +passwd jack +``` + +2. Add user to opener + +Add one or more pf rules to user file. + +```bash +vi firewall/user/jack +``` +An example to allow user jack to make RDP connections to host 192.168.2.12: + +`pass in proto tcp from IP to $wan port 63389 rdr-to 192.168.2.12 port 3388` + +The `$wan` changes according to the address of the SSH connection that the user makes every time + +## Todo + +- chroot shell +- email activity diff --git a/etc/dhcpd.conf b/etc/dhcpd.conf new file mode 100644 index 0000000..e29e1dd --- /dev/null +++ b/etc/dhcpd.conf @@ -0,0 +1,8 @@ +option domain-name "taxstudio.gr"; +option domain-name-servers 9.9.9.9; + +subnet 192.168.2.0 netmask 255.255.255.0 { + option routers 192.168.2.1; + range 192.168.2.11 192.168.2.19; +} + diff --git a/etc/dhcpd.interfaces b/etc/dhcpd.interfaces new file mode 100644 index 0000000..3dcb18f --- /dev/null +++ b/etc/dhcpd.interfaces @@ -0,0 +1 @@ +stge0 diff --git a/etc/hostname.em0 b/etc/hostname.em0 new file mode 100644 index 0000000..72ab18f --- /dev/null +++ b/etc/hostname.em0 @@ -0,0 +1 @@ +dhcp diff --git a/etc/hostname.stge0 b/etc/hostname.stge0 new file mode 100644 index 0000000..a28195f --- /dev/null +++ b/etc/hostname.stge0 @@ -0,0 +1,4 @@ +media 100baseTX +mediaopt full-duplex +inet 192.168.2.1 0xffffff00 + diff --git a/etc/pf.conf b/etc/pf.conf new file mode 100644 index 0000000..aedb3e2 --- /dev/null +++ b/etc/pf.conf @@ -0,0 +1,41 @@ +wan = em0 +lan = stge0 + +#---------------------------------- +# Defaults +#---------------------------------- +pass out keep state + +set skip on lo +set block-policy return +set reassemble yes + +block in all +block return + +match in on $wan scrub (no-df max-mss 1440) +match out on $wan scrub (random-id) + +antispoof quick for { $wan lo0 } + +#---------------------------------- +# Input +#---------------------------------- +pass quick on $lan +pass in quick proto tcp to $wan port 22 keep state +pass in quick on $lan + +#---------------------------------- +# Output +#---------------------------------- +pass out on $lan inet keep state + +#---------------------------------- +# NAT +#---------------------------------- +match out on $wan from !($wan) nat-to ($wan) + +# Allow outgoing traffic for LAN and the gateway +pass out quick keep state +pass in on { $lan } inet + diff --git a/etc/rc.d/dhcpd b/etc/rc.d/dhcpd new file mode 100755 index 0000000..30a4dcd --- /dev/null +++ b/etc/rc.d/dhcpd @@ -0,0 +1,15 @@ +#!/bin/ksh +# +# $OpenBSD: dhcpd,v 1.3 2018/01/11 19:52:12 rpe Exp $ + +daemon="/usr/sbin/dhcpd" + +. /etc/rc.d/rc.subr + +rc_reload=NO + +rc_pre() { + touch /var/db/dhcpd.leases +} + +rc_cmd $1 diff --git a/etc/rc.d/sshd b/etc/rc.d/sshd new file mode 100755 index 0000000..94cc554 --- /dev/null +++ b/etc/rc.d/sshd @@ -0,0 +1,15 @@ +#!/bin/ksh +# +# $OpenBSD: sshd,v 1.6 2020/01/25 12:05:08 sthen Exp $ + +daemon="/usr/sbin/sshd" + +. /etc/rc.d/rc.subr + +pexp="sshd: ${daemon}${daemon_flags:+ ${daemon_flags}} \[listener\].*" + +rc_reload() { + ${daemon} ${daemon_flags} -t && pkill -HUP -xf "${pexp}" +} + +rc_cmd $1 diff --git a/etc/ssh/sshd_config b/etc/ssh/sshd_config new file mode 100644 index 0000000..a2cc3c5 --- /dev/null +++ b/etc/ssh/sshd_config @@ -0,0 +1,93 @@ +# $OpenBSD: sshd_config,v 1.103 2018/04/09 20:41:22 tj Exp $ + +# This is the sshd server system-wide configuration file. See +# sshd_config(5) for more information. + +# The strategy used for options in the default sshd_config shipped with +# OpenSSH is to specify options with their default value where +# possible, but leave them commented. Uncommented options override the +# default value. + +#Port 22 +#AddressFamily any +#ListenAddress 0.0.0.0 +#ListenAddress :: + +#HostKey /etc/ssh/ssh_host_rsa_key +#HostKey /etc/ssh/ssh_host_ecdsa_key +#HostKey /etc/ssh/ssh_host_ed25519_key + +# Ciphers and keying +#RekeyLimit default none + +# Logging +#SyslogFacility AUTH +#LogLevel INFO + +# Authentication: + +#LoginGraceTime 2m +PermitRootLogin yes +#StrictModes yes +#MaxAuthTries 6 +#MaxSessions 10 + +#PubkeyAuthentication yes + +# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 +# but this is overridden so installations will only check .ssh/authorized_keys +AuthorizedKeysFile .ssh/authorized_keys + +#AuthorizedPrincipalsFile none + +#AuthorizedKeysCommand none +#AuthorizedKeysCommandUser nobody + +# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts +#HostbasedAuthentication no +# Change to yes if you don't trust ~/.ssh/known_hosts for +# HostbasedAuthentication +#IgnoreUserKnownHosts no +# Don't read the user's ~/.rhosts and ~/.shosts files +#IgnoreRhosts yes + +# To disable tunneled clear text passwords, change to no here! +#PasswordAuthentication yes +#PermitEmptyPasswords no + +# Change to no to disable s/key passwords +#ChallengeResponseAuthentication yes + +#AllowAgentForwarding yes +#AllowTcpForwarding yes +#GatewayPorts no +#X11Forwarding no +#X11DisplayOffset 10 +#X11UseLocalhost yes +#PermitTTY yes +#PrintMotd yes +#PrintLastLog yes +#TCPKeepAlive yes +#PermitUserEnvironment no +#Compression delayed +#ClientAliveInterval 0 +#ClientAliveCountMax 3 +#UseDNS no +#PidFile /var/run/sshd.pid +#MaxStartups 10:30:100 +#PermitTunnel no +#ChrootDirectory none +#VersionAddendum none + +# no default banner path +#Banner none + +# override default of no subsystems +Subsystem sftp /usr/libexec/sftp-server + +# Example of overriding settings on a per-user basis +#Match User anoncvs +# X11Forwarding no +# AllowTcpForwarding no +# PermitTTY no +# ForceCommand cvs server diff --git a/etc/sysctl.conf b/etc/sysctl.conf new file mode 100644 index 0000000..cd3cf17 --- /dev/null +++ b/etc/sysctl.conf @@ -0,0 +1 @@ +net.inet.ip.forwarding=1 diff --git a/firewall/fw-allow.sh b/firewall/fw-allow.sh new file mode 100644 index 0000000..f5a7586 --- /dev/null +++ b/firewall/fw-allow.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env ksh + +# +# Forward Opener (server helper) +# +# for OpenBSD +# by ste.vaidis@gmail.com +# + +if [ $# -ne 2 ]; then + logger -t "FORWARD" "fw-allow.sh executed without proper arguments: user:$1 ip:$2" + exit +fi + +USER=$1 +IP=$2 + +logger -t "FORWARD" "Open for user $USER from $IP" + +cat /firewall/user/$USER | sed "s/IP/$IP/g" > /firewall/user/$USER.tmp +echo "include '/firewall/user/$USER.tmp'" >> /etc/pf.conf +if [[ $? != 0 ]]; then echo "Fail"; fi + +pfctl -f /etc/pf.conf +if [[ $? != 0 ]]; then echo "Fail"; fi + +sleep 15 +if [[ $? != 0 ]]; then echo "Fail"; fi + +sed -i "/$USER/d" /etc/pf.conf +if [[ $? != 0 ]]; then echo "Fail"; fi + +pfctl -f /etc/pf.conf +if [[ $? != 0 ]]; then echo "Fail"; fi + +logger -t "FORWARD" "Close for user $USER from $IP" + +rm /firewall/user/$USER.tmp + +exit diff --git a/firewall/fw-server.sh b/firewall/fw-server.sh new file mode 100644 index 0000000..4f19248 --- /dev/null +++ b/firewall/fw-server.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env ksh + +# +# Forward Opener (server) +# +# for OpenBSD +# by ste.vaidis@gmail.com +# + +/usr/local/bin/ncat -lk localhost 3000 | ( + while read c; do + USER=$(echo $c | awk {'print $1'}) + IP=$(echo $c | awk {'print $2'}) + ps x | grep fw-allow.sh | grep $USER | grep -v grep + if [ $? -eq 1 ]; then + /firewall/fw-allow.sh $USER $IP + fi + done +) diff --git a/firewall/fw.sh b/firewall/fw.sh new file mode 100644 index 0000000..0ef4907 --- /dev/null +++ b/firewall/fw.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env ksh + +# +# Let-Me-In (client) +# +# for OpenBSD +# by ste.vaidis@gmail.com +# + +TITLE="OpenBSD Firewall" +USER=$(whoami) +IP=$(w | grep $USER | awk {'print $3'}) + +echo "$USER $IP" | nc -w1 localhost 3000 & + +( + items=15 + processed=0 + while [ $processed -le $items ]; do + pct=$(( $processed * 100 / $items )) + echo "XXX\n" + echo "\nHello $USER from $IP" + echo "\nYou have 15 seconds to connect ($processed)" + echo "XXX" + echo "$pct" + processed=$((processed+1)) + sleep 1 + done +) | dialog --title "$TITLE" --gauge "\nWait please..." 10 50 0 \ No newline at end of file diff --git a/firewall/user/bob b/firewall/user/bob new file mode 100644 index 0000000..6f7f026 --- /dev/null +++ b/firewall/user/bob @@ -0,0 +1 @@ +pass in log proto tcp to $wan port 60122 rdr-to 192.168.2.11 port 22 diff --git a/firewall/user/jack b/firewall/user/jack new file mode 100644 index 0000000..d6e4706 --- /dev/null +++ b/firewall/user/jack @@ -0,0 +1,2 @@ +pass in proto tcp from IP to $wan port 63389 rdr-to 192.168.2.222 port 3388 +pass in proto tcp from IP to $wan port 60322 rdr-to 192.168.2.222 port 22 \ No newline at end of file diff --git a/forward_opener.png b/forward_opener.png new file mode 100644 index 0000000..e744d2c Binary files /dev/null and b/forward_opener.png differ