Ξ welcome to cryptostorm's member forums ~ you don't have to be a cryptostorm member to post here Ξ
∞ take a peek at our legendary cryptostorm_is twitter feed if you're into that kind of thing ∞
Ξ we're rolling out voodoo network security across cryptostorm - big things happening, indeed! Ξ
Ξ any OpenVPN configs found on the forum are likely outdated. For the latest, visit GitHub Ξ

My connection script

Freewheeling spot to chew the fat on anything cryptostorm-related that doesn't fit elsewhere (i.e. support, howto, &c.). Criticism & praise & brainstorming & requests for explanation... this is where it goes when it's hot & ready for action! :-)

Topic Author
devnope
Posts: 2
Joined: Fri Jan 06, 2017 11:02 pm

My connection script

Postby devnope » Fri Jan 06, 2017 11:16 pm

Hi guys, I thought I'd share with you a script I wrote to help prevent leaks on Linux.
Comments/improvements are appreciated.

The README:

Code: Select all

This script will:

- Block all IPv6 traffic (except for loopback, which is needed for some applications to work correctly).
- Convert all hostnames in (a copy of) the given ovpn file to the corresponding IP addresses (so we can disable clear DNS traffic altogether).
- Block all outgoing DNS IPv4 traffic.
- Block all outgoing non-DNS IPv4 traffic except:
-- Traffic to the remotes specified in the ovpn file,
-- Traffic the the local subnets for all your interfaces,
-- Traffic to the openvpn tunnel (obviously!).
- Block all incoming traffic that does not belong to connections we initiated.
- Run openvpn and drop privileges to the 'nobody' user and its group. Scripts to take care of updating the DNS to the one provided by the remote are used (you need resolvconf).
- Cleanup and restore internect access on SIGINT (ctrl+c)
- In case openvpn dies, it will explictly wait for input before restoring Internet access.

WARNING: This scrip will flush your custom iptable rules and chains, if you have any.

0) OPTIONAL BUT RECOMMENDED: READ AND UNDERSTAND THE CODE BEFORE RUNNING IT!!

1) Install resolvconf (e.g., using your distro package manager).

2) Save the script somewhere (i.e., connect.sh) and make the file executable:

$ chmod +x connect.sh

3) Create a file named auth with your username (i.e., token (or just anything for cryptofree)) on the first line of the file, and your password (i.e., anything) on the second line:

$ echo "user" > auth
$ echo "password" >> auth

You probably want this file to be for your eyes only:

$ chmod 600 auth

Save your .ovpn configs of choice:

4) wget https://raw.githubusercontent.com/cryptostorm/cryptostorm_client_configuration_files/master/cryptofree/cryptofree_linux-udp.ovpn

Run the script (as root):

# ./connect.sh cryptofree_linux-udp.ovpn

5) Enjoy


The script:

Code: Select all

#!/bin/sh

#Default OpenVPN config file
OVPN_FILE="cryptofree_linux-udp.ovpn"

#Credentials file
AUTH_FILE="auth"

#Drop privileges to this user and group
DUSER="nobody"
DGROUP=$(id -g -n "$DUSER")

#tun device name
TUN_NAME="tun-cs"

#temporary file name
TMP_FILE="tmp.ovpn"

trap sigint INT

cleanup () {
   echo "Removing IPv4 iptables rules"
   iptables -F
   iptables -X

   echo "Unblocking IPv6"
   ip6tables -F
   ip6tables -X

   echo "Removing stray resolvconf file (as OpenVPN cannot remove it due to privilege drop)"
   resolvconf -d "tun-cs.openvpn"

   echo "Removing temporary OpenVPN configuration"
   rm "$TMP_FILE"
}

sigint () {
   echo "SIGINT Caught. Cleaning up and exiting"
   cleanup
   exit 0
}

if [ "$(id -u)" -ne "0" ]; then
   echo "You must be root"
   exit 1
fi

if [ ! -z "$1" ]; then
   OVPN_FILE="$1"
fi

echo "Using config file '$OVPN_FILE'"

echo "Blocking IPv6 (exept for loopback)"
ip6tables -F
ip6tables -X
ip6tables -A INPUT -i lo -j ACCEPT
ip6tables -A INPUT   -j DROP
ip6tables -A FORWARD -j DROP
ip6tables -A OUTPUT -o lo -j ACCEPT
ip6tables -A OUTPUT  -j DROP

echo "Adding IPv4 iptables rules"
iptables -F
iptables -X

iptables -N allow_cryptostorm_servers

awk '/remote / {print "#"$0; next} {print $0}' cryptofree_windows-tcp.ovpn > "$TMP_FILE"

cat "$OVPN_FILE" | grep -oE "^remote [[:alnum:].-]+ [[:digit:]]+ (tcp|udp)" | while read -r remote; do
   host=$(echo "$remote" | cut -d " " -f 2)
   port=$(echo "$remote" | cut -d " " -f 3)
   proto=$(echo "$remote" | cut -d " " -f 4)

   echo "Found remote $host:port with protocol $proto"

   if echo "$host" | grep -Eq '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'; then
      echo "Host is an IP address. Allowing traffic to: $host on port $port with protocol $proto"
      iptables -A allow_cryptostorm_servers -p "$proto" --destination "$host" --dport "$port" -j ACCEPT
      echo "remote $host $port $proto" >> "$TMP_FILE"
   else
      echo "Host is a domain name. Resolving..."
      for ip in $(dig -4 -t A -q "$host" +short); do
         echo "Allowing traffic to: $ip on port $port with protocol $proto"
         iptables -A allow_cryptostorm_servers -p "$proto" --destination "$ip" --dport "$port" -j ACCEPT
         echo "remote $ip $port $proto" >> "$TMP_FILE"
      done
   fi
done

iptables -A allow_cryptostorm_servers -j RETURN

iptables -A INPUT -m state --state INVALID -j DROP
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -j DROP

#echo "Blocking traffic to 192.0.2.0/24 subnet (TEST-NET subnet, it should be non-public anyway  RFC 5737)"
#iptables -A OUTPUT --destination 192.0.2.0/24 -j DROP

echo "Blocking DNS traffic"
iptables -A OUTPUT -p tcp --dport 53 -j DROP
iptables -A OUTPUT -p udp --dport 53 -j DROP

#for ns in $(grep -Eo '^nameserver[[:space:]]+[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$' /etc/resolv.conf | awk '{print $2}'); do
#       echo "Explicitly allowing udp traffic to DNS server $ns (port 53)"
#       iptables -A OUTPUT -p "udp" --destination "$ns" --dport 53 -j ACCEPT
#done


for iface in $(ip -brief link show up | awk '{print $1}'); do
   local_nets=$(ip -brief -f inet addr show "$iface" | awk '{for(i=3;i<=NF;i++) print $i}' )
   for net in $local_nets; do
      echo "Allowing traffic to $net on interface $iface"
      iptables -A OUTPUT -o "$iface" --destination "$net" -j ACCEPT
   done
done

iptables -A OUTPUT -j allow_cryptostorm_servers
iptables -A OUTPUT -o "$TUN_NAME" -j ACCEPT
iptables -A OUTPUT -j DROP

iptables -A FORWARD -j DROP

echo "Will drop privileges to user $DUSER and group $DGROUP"

echo "Starting OpenVPN process (tunnel device name: $TUN_NAME)"
openvpn --config "$TMP_FILE" --dev tun-cs --dev-type tun --auth-user-pass "$AUTH_FILE" --user "$DUSER" --group "$DGROUP" --persist-tun --persist-key --script-security 2 --up /etc/openvpn/update-resolv-conf  --down /etc/openvpn/update-resolv-conf --verb 3 #--dhcp-option "DNS 192.0.2.1" --dhcp-option "DNS 192.0.2.2"

echo "OpenVPN process ended. Press enter to restore Internet access"
read wait; unset wait

cleanup

exit 0


Topic Author
devnope
Posts: 2
Joined: Fri Jan 06, 2017 11:02 pm

Re: My connection script

Postby devnope » Sat Jan 07, 2017 2:37 am

Fixing a hardcoded filename and limiting remotes to 64 (openvpn complains with more remotes).

Code: Select all

#!/bin/sh

#Default OpenVPN config file
OVPN_FILE="cryptostorm_client_configuration_files-master/linux/cstorm_linux-dynamic_udp.ovpn"

#Credentials file
AUTH_FILE="auth"

#Drop privileges to this user and group
DUSER="nobody"
DGROUP=$(id -g -n "$DUSER")

#tun device name
TUN_NAME="tun-cs"

#temporary file name
TMP_FILE="tmp.ovpn"

MAX_REMOTES=64

trap sigint INT

cleanup () {
   echo "Removing IPv4 iptables rules"
   iptables -F
   iptables -X

   echo "Unblocking IPv6"
   ip6tables -F
   ip6tables -X

   echo "Removing stray resolvconf file (as OpenVPN cannot remove it due to privilege drop)"
   resolvconf -d "tun-cs.openvpn"

   echo "Removing temporary OpenVPN configuration"
   rm "$TMP_FILE"
}

sigint () {
   echo "SIGINT Caught. Cleaning up and exiting"
   cleanup
   exit 0
}


add_remote () {
        nremotes=$(($nremotes + 1))

   if [ $nremotes -ge 64 ]; then
      echo "Ignoring remote $nremotes/$MAX_REMOTES"
   else
           echo "Allowing traffic to: $1 on port $2 with protocol $3 ($nremotes/$MAX_REMOTES)"
           iptables -A allow_cryptostorm_servers -p "$3" --destination "$1" --dport "$2" -j ACCEPT
           echo "remote $1 $2 $3" >> "$TMP_FILE"
   fi
}

if [ "$(id -u)" -ne "0" ]; then
   echo "You must be root"
   exit 1
fi

if [ ! -z "$1" ]; then
   OVPN_FILE="$1"
fi

echo "Using config file '$OVPN_FILE'"

echo "Blocking IPv6 (exept for loopback)"
ip6tables -F
ip6tables -X
ip6tables -A INPUT -i lo -j ACCEPT
ip6tables -A INPUT   -j DROP
ip6tables -A FORWARD -j DROP
ip6tables -A OUTPUT -o lo -j ACCEPT
ip6tables -A OUTPUT  -j DROP

echo "Adding IPv4 iptables rules"
iptables -F
iptables -X

iptables -N allow_cryptostorm_servers

awk '/remote / {print "#"$0; next} {print $0}' "$OVPN_FILE" > "$TMP_FILE"

nremotes=0
cat "$OVPN_FILE" | grep -oE "^remote [[:alnum:].-]+ [[:digit:]]+ (tcp|udp)" | shuf | while read -r remote; do
   host=$(echo "$remote" | cut -d " " -f 2)
   port=$(echo "$remote" | cut -d " " -f 3)
   proto=$(echo "$remote" | cut -d " " -f 4)

   echo "Found remote $host:port with protocol $proto"

   if echo "$host" | grep -Eq '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'; then
      nremotes=$(($nremotes + 1))
      echo "Host is an IP address."
      add_remote "$host" "$port" "$proto"
   else
      echo "Host is a domain name. Resolving..."
      for ip in $(dig -4 -t A -q "$host" +short); do
         add_remote "$ip" "$port" "$proto"
      done
   fi
done

iptables -A allow_cryptostorm_servers -j RETURN

iptables -A INPUT -m state --state INVALID -j DROP
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -j DROP

#echo "Blocking traffic to 192.0.2.0/24 subnet (TEST-NET subnet, it should be non-public anyway  RFC 5737)"
#iptables -A OUTPUT --destination 192.0.2.0/24 -j DROP

#for ns in $(grep -Eo '^nameserver[[:space:]]+[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$' /etc/resolv.conf | awk '{print $2}'); do
#       echo "Explicitly allowing udp traffic to DNS server $ns (port 53)"
#       iptables -A OUTPUT -p "udp" --destination "$ns" --dport 53 -j ACCEPT
#done


for iface in $(ip -brief link show up | awk '{print $1}'); do
   local_nets=$(ip -brief -f inet addr show "$iface" | awk '{for(i=3;i<=NF;i++) print $i}' )
   for net in $local_nets; do
      echo "Allowing traffic to $net on interface $iface"
      iptables -A OUTPUT -o "$iface" --destination "$net" -j ACCEPT
   done
done

iptables -A OUTPUT -j allow_cryptostorm_servers
iptables -A OUTPUT -o "$TUN_NAME" -j ACCEPT

echo "Blocking DNS traffic"
iptables -A OUTPUT -p tcp --dport 53 -j DROP
iptables -A OUTPUT -p udp --dport 53 -j DROP

iptables -A OUTPUT -j DROP

iptables -A FORWARD -j DROP

echo "Will drop privileges to user $DUSER and group $DGROUP"

echo "Starting OpenVPN process (tunnel device name: $TUN_NAME)"
openvpn --config "$TMP_FILE" --dev tun-cs --dev-type tun --auth-user-pass "$AUTH_FILE" --user "$DUSER" --group "$DGROUP" --persist-tun --persist-key --script-security 2 --up /etc/openvpn/update-resolv-conf  --down /etc/openvpn/update-resolv-conf --verb 3 #--dhcp-option "DNS 192.0.2.1" --dhcp-option "DNS 192.0.2.2"

echo "OpenVPN process ended. Press enter to restore Internet access"
read wait; unset wait

cleanup

exit 0


c_2212

Re: My connection script

Postby c_2212 » Thu Feb 09, 2017 11:29 pm

Code: Select all

./connect.sh: line 100: dig: command not found
Allowing traffic to 127.0.0.1/8 on interface lo
Allowing traffic to 192.168.1.35/24 on interface enp0s25
Allowing traffic to 192.168.122.1/24 on interface virbr0
Blocking DNS traffic
Will drop privileges to user nobody and group nobody
Starting OpenVPN process (tunnel device name: tun-cs)
Options error: --nobind doesn't make sense unless used with --remote
Use --help for more information.
OpenVPN process ended. Press enter to restore Internet access

Removing IPv4 iptables rules
Unblocking IPv6
Removing stray resolvconf file (as OpenVPN cannot remove it due to privilege drop)
No resolv.conf for interface tun-cs.openvpn
Removing temporary OpenVPN configuration


I don't get it.

User avatar

df
Site Admin
Posts: 285
Joined: Thu Jan 01, 1970 5:00 am

Re: My connection script

Postby df » Mon Sep 18, 2017 5:00 pm

@c_2212

./connect.sh: line 100: dig: command not found


That script uses the `dig` command to resolve hostnames, and your system either doesn't have it installed, or it's not in a location that's listed in the $PATH environment variable.

Here's a modified version that includes some code to check for and use either `dig`, `host`, or `nslookup` for resolving hostnames:

Code: Select all

#!/bin/sh

#Default OpenVPN config file
OVPN_FILE="cryptostorm_client_configuration_files-master/linux/cstorm_linux-dynamic_udp.ovpn"

#Credentials file
AUTH_FILE="auth"

#Drop privileges to this user and group
DUSER="nobody"
DGROUP=$(id -g -n "$DUSER")

#tun device name
TUN_NAME="tun-cs"

#temporary file name
TMP_FILE="tmp.ovpn"

MAX_REMOTES=64

trap sigint INT

cleanup () {
   echo "Removing IPv4 iptables rules"
   iptables -F
   iptables -X

   echo "Unblocking IPv6"
   ip6tables -F
   ip6tables -X

   echo "Removing stray resolvconf file (as OpenVPN cannot remove it due to privilege drop)"
   resolvconf -d "tun-cs.openvpn"

   echo "Removing temporary OpenVPN configuration"
   rm "$TMP_FILE"
}

sigint () {
   echo "SIGINT Caught. Cleaning up and exiting"
   cleanup
   exit 0
}


add_remote () {
   nremotes=$(($nremotes + 1))

   if [ $nremotes -ge 64 ]; then
      echo "Ignoring remote $nremotes/$MAX_REMOTES"
   else
           echo "Allowing traffic to: $1 on port $2 with protocol $3 ($nremotes/$MAX_REMOTES)"
           iptables -A allow_cryptostorm_servers -p "$3" --destination "$1" --dport "$2" -j ACCEPT
           echo "remote $1 $2 $3" >> "$TMP_FILE"
   fi
}

command -v dig >/dev/null 2>&1
if [ $? == 0 ]; then
   resolve() {
      dig -4 -t A -q "$1" +short
   }
fi
command -v host >/dev/null 2>&1
if [ $? == 0 ]; then
   resolve() {
      host "$1" 2>/dev/null|grep 'has a'|awk '{print $NF}'
   }
fi
command -v nslookup >/dev/null 2>&1
if [ $? == 0 ]; then
   resolve () {
      nslookup "$1" | tail -n +3 | sed -n 's/Address:\s*//p'
   }
fi
type resolve >/dev/null 2>&1
if [ $? != 0 ]; then
   echo "Could not find a program to resolve hostnames"
   exit 1
fi

if [ "$(id -u)" -ne "0" ]; then
   echo "You must be root"
   exit 1
fi

if [ ! -z "$1" ]; then
   OVPN_FILE="$1"
fi

echo "Using config file '$OVPN_FILE'"

echo "Blocking IPv6 (exept for loopback)"
ip6tables -F
ip6tables -X
ip6tables -A INPUT -i lo -j ACCEPT
ip6tables -A INPUT   -j DROP
ip6tables -A FORWARD -j DROP
ip6tables -A OUTPUT -o lo -j ACCEPT
ip6tables -A OUTPUT  -j DROP

echo "Adding IPv4 iptables rules"
iptables -F
iptables -X

iptables -N allow_cryptostorm_servers

awk '/remote / {print "#"$0; next} {print $0}' "$OVPN_FILE" > "$TMP_FILE"

nremotes=0
cat "$OVPN_FILE" | grep -oE "^remote [[:alnum:].-]+ [[:digit:]]+ (tcp|udp)" | shuf | while read -r remote; do
   host=$(echo "$remote" | cut -d " " -f 2)
   port=$(echo "$remote" | cut -d " " -f 3)
   proto=$(echo "$remote" | cut -d " " -f 4)

   echo "Found remote $host:port with protocol $proto"

   if echo "$host" | grep -Eq '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'; then
      nremotes=$(($nremotes + 1))
      echo "Host is an IP address."
      add_remote "$host" "$port" "$proto"
   else
      echo "Host is a domain name. Resolving..."
      for ip in $(resolve "$host"); do
         add_remote "$ip" "$port" "$proto"
      done
   fi
done

iptables -A allow_cryptostorm_servers -j RETURN

iptables -A INPUT -m state --state INVALID -j DROP
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -j DROP

#echo "Blocking traffic to 192.0.2.0/24 subnet (TEST-NET subnet, it should be non-public anyway  RFC 5737)"
#iptables -A OUTPUT --destination 192.0.2.0/24 -j DROP

#for ns in $(grep -Eo '^nameserver[[:space:]]+[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$' /etc/resolv.conf | awk '{print $2}'); do
#       echo "Explicitly allowing udp traffic to DNS server $ns (port 53)"
#       iptables -A OUTPUT -p "udp" --destination "$ns" --dport 53 -j ACCEPT
#done


for iface in $(ip -brief link show up | awk '{print $1}'); do
   local_nets=$(ip -brief -f inet addr show "$iface" | awk '{for(i=3;i<=NF;i++) print $i}' )
   for net in $local_nets; do
      echo "Allowing traffic to $net on interface $iface"
      iptables -A OUTPUT -o "$iface" --destination "$net" -j ACCEPT
   done
done

iptables -A OUTPUT -j allow_cryptostorm_servers
iptables -A OUTPUT -o "$TUN_NAME" -j ACCEPT

echo "Blocking DNS traffic"
iptables -A OUTPUT -p tcp --dport 53 -j DROP
iptables -A OUTPUT -p udp --dport 53 -j DROP

iptables -A OUTPUT -j DROP

iptables -A FORWARD -j DROP

echo "Will drop privileges to user $DUSER and group $DGROUP"

echo "Starting OpenVPN process (tunnel device name: $TUN_NAME)"
openvpn --config "$TMP_FILE" --dev tun-cs --dev-type tun --auth-user-pass "$AUTH_FILE" --user "$DUSER" --group "$DGROUP" --persist-tun --persist-key --script-security 2 --up /etc/openvpn/update-resolv-conf  --down /etc/openvpn/update-resolv-conf --verb 3 #--dhcp-option "DNS 192.0.2.1" --dhcp-option "DNS 192.0.2.2"

echo "OpenVPN process ended. Press enter to restore Internet access"
read wait; unset wait

cleanup

exit 0


Another improvement that might help is adding more checks for commands like `iptables`, since that's often in /sbin/ and /sbin/ is sometimes not in the $PATH environment variable. Same goes for `ip6tables`.


Return to “general chat, suggestions, industry news”

Who is online

Users browsing this forum: No registered users and 16 guests

cron

Login