As I build more and more Pi-based systems, I find the need to add management scripts for accessing SSH, OpenVPN, and all kinds of other tools. This leads me to version 4 of the CloudFlare Dynamic DNS AutoIP updater script. It’s now hosted on GitHub.

Pulling off of GitHub:


Cloudflare-Subdomain-AutoIP-Updater

Create a private Dynamic DNS using the CloudFlare API with this script.

If you have a domain registered at CloudFlare, you can use this script to update the IP of the subdomain with a specific computer. The computer will get its IP address and send the information to CloudFlare using the API.

This script creates 3 files:

  1. an initializing script that creates and runs everything: cf_ip_script_creator.sh
  2. a script that gets all the CF details from you: cf_ip_updater_creator.sh
  3. a script that updates the subdomain IP address: cf_ip_updater.sh

Put the 3rd script (cf_ip_updater.sh) into a cron job to run every 5 or 15 minutes or so so that you can use access your system anywhere.

  sudo crontab -e
  
  */10 * * * *  nice -n 16 /home/scripts/cf_ip_updater.sh

Potential uses:

  • log into your computer anytime with SSH
  • run a portable OpenVPN server
  • keep your blog server private by using CloudFlare caching
  • whatever you can think of

Some potential issues:

  • if you fail to successfully run the script, the cat commands that append text to existing commands will force you to delete the create scripts (cf_ip_updater.sh, cf_ip_updater_creator.sh) before you run the initializing script (cf_ip_script_creator.sh) again.

You need the following information:

  • FULLDOMAIN cloudflare.com (your registered domain name)
  • SUBDOMAIN web.cloudflare.com (your subdomain linked to your system’s IP address)
  • EMAIL [email protected] (your account name)
  • KEY 9a7806061c88ada191ed06f989cc3dac (your CloudFlare API key details)
  • FILEPATH /home/path (where you want the script to be)

How to run:

  wget https://raw.githubusercontent.com/tgmgroup/Cloudflare-Subdomain-AutoIP-Updater/master/cf_ip_script_creator.sh
  chmod +X cf_ip_script_creator.sh
  sudo bash cf_ip_script_creator.sh

Dependencies:

  • The jq command requires the jq package (sudo apt install jq)
  • The dig command requires dnsutils (Debian) or bind-utils (Cent-OS) (sudo apt install dnsutils)

Read more at:

The last few days, I’ve been working on a vpn server for my home network. It’s so that my family all over the world can see the pictures of my son, which are hosted on a local server. However, I don’t want to expose those pictures to the world, hence the need for a vpn.

While using PiVPN to set up an OpenVPN server, I ran the script once and, since I hadn’t finished everything yet, I selected the Static IP option for the server. Since I was close to finishing all the setup, I wondered, how do you change the PiVPN OpenVPN config to use either a static ip address or dynamic domain name after running the initial configuration script?

It’s not difficult to change this in the ovpn config files that PiVPN generates, and OpenVPN apparently doesn’t care if the server name is an IP or a domain, so long as the client reaches the vpn server. However, I like to be a little bit of a perfectionist and it makes sense to change it to make future client configuration issues easier.

So after searching the PiVPN git page and the local /etc/ directories, I realized that the place to change the server name option was in this file:

/etc/openvpn/easy-rsa/keys/Default.txt

Just run a simple sudo nano /etc/openvpn/easy-rsa/keys/Default.txt command to edit the “remote” field:

client
dev tun
proto udp
remote Your-Domain-Name Your-Port-Number
resolv-retry infinite

Then run the pivpn add command to create a new client, and use sudo nano /home/pi/ovpns/Your-New-Client.ovpn to check to see that the domain name is being used instead of a static IP.

 

 

Photo by Nguyen Vu Hung (vuhung)

 

I talked about how to use PiVPN to set up an OpenVPN server on a Raspberry Pi at home previously, here and here. The next step for me was to use CloudFlare as a DNS server, instead of signing up for yet another internet service and having another login here or there to worry about.

This very smart guy, Tomasso Barbato, wrote up how to do it, but he includes two versions, an APIvUnknown and an APIv4 version. CloudFlare only supports the APIv4 version as of next month, I guess, so I’m copying the scripts here, as many of my referenced internet pages have gone offline in recent months. Read his page, though, so that you know what to do. I’ve also bolded the variables so that you can simply run a Replace All command in a text editor to easily adapt the scripts for your use. An enterprising hacker would create a bash script to automate all the other scripts, but…

Initial setup

This should be pretty easy, but:

  1. Go to CloudFlare
  2. Add an A record to your domain through the DNS page
  3. Use your current IP address of your server for the record
  4. Read the page to learn how to do it, but use my edits for an easier time.

The important variables

FULL-DOMAIN: example.com
SUB-DOMAIN: sub.example.com

From the CloudFlare user settings page

EMAIL: Account Email:    X-Auth-Email: [email protected]
KEY: API Key:    X-Auth-Key: 9a7806061c88ada191ed06f989cc3dac

*Note: the API Key is the shorter of the two keys that you have the option of requesting

Use scripts to obtain

ZONE-ID: Zone ID (domain name): “id”: “dac9320b638f5e225cf483cc5cfdda41”
RECORD-ID: Record ID (subdomain/A record): “id”: “8ada191ed06f989cc3dac9a7806061c8”

*Note: I’m using a VARIABLE: explanation: example format here.

The scripts

Get Zone ID:
curl -X GET "https://api.cloudflare.com/client/v4/zones?name=FULL-DOMAIN" \
  -H "X-Auth-Email: EMAIL" \
  -H "X-Auth-Key: KEY" \
  -H "Content-Type: application/json" | jq .
Get Record ID:
curl -X GET "https://api.cloudflare.com/client/v4/zones/ZONE-ID/dns_records?name=SUB-DOMAIN" \
  -H "X-Auth-Email: EMAIL" \
  -H "X-Auth-Key: KEY" \
  -H "Content-Type: application/json" | jq .
Bash script for crontab
#!/bin/sh

[ ! -f /var/tmp/current_ip.txt ] && touch /var/tmp/currentip.txt

NEWIP=`dig +short myip.opendns.com @resolver1.opendns.com`
CURRENTIP=`cat /var/tmp/currentip.txt`

if [ "$NEWIP" = "$CURRENTIP" ]
then
  echo "IP address unchanged"
else
  curl -X PUT "https://api.cloudflare.com/client/v4/zones/ZONE-ID/dns_records/RECORD-ID" \
    -H "X-Auth-Email: EMAIL" \
    -H "X-Auth-Key: KEY" \
    -H "Content-Type: application/json" \
    --data "{\"type\":\"A\",\"name\":\"SUB-DOMAIN\",\"content\":\"$NEWIP\"}"
  echo $NEWIP > /var/tmp/currentip.txt
fi

 

By using this script, I now have an OpenVPN server that is somewhat protected by CloudFlare that I can access anywhere and whenever I want, no matter if my home router reboots or if I change internet providers.

There is a caveat: CloudFlare can only protect ports that are used with HTTP HOST headers, SSH or OpenVPN or any other protocol requires the A record to disable its CloudFlare protection. This exposes your IP address somewhat, but it is also protected somewhat. There’s a tradeoff between domain name privacy and personal convenience here.

I also read that a SRV record hides the IP of an origin server better than an A record, so that’s a logical next step, but not one that I have time for right now.

 

Photo by Nguyen Vu Hung (vuhung)

 

Security@Georgeliu.me

Before, I had written about a CloudFlare auto-ip-updating script, but it required a lot of user input and a lot of user effort. Luckily, or not, I  crashed my OMV server, and I think an error ate up my PiVPN sd card. So I had to start all over!

This time, I updated the CloudFlare script to be auto-updating.

This bash script requires the following inputs in this order (INFO example):

  • FULLDOMAIN cloudflare.com
  • SUBDOMAIN web.cloudflare.com
  • EMAIL [email protected]
  • KEY 9a7806061c88ada191ed06f989cc3dac
  • FILEPATH /home/path

If you organize your inputs in this order, it is very easy to copy once and paste to get your results.

Create and Run Script

Create a script and paste the following code in:

sudo nano cf_ip_updater_creater.sh

sudo chmod +x cf_ip_updater_creater.sh
./cf_ip_updater_creater.sh
Script Code
#!/bin/sh

#Get User Data
echo -n "Enter your FULL-DOMAIN (e.g. cloudflare.com) and press [ENTER]: "
read FULLDOMAIN

echo -n "Enter your SUB-DOMAIN (e.g. web.cloudflare.com) and press [ENTER]: "
read SUBDOMAIN

echo -n "Enter your Cloudflare Email (e.g. [email protected]) and press [ENTER]: "
read EMAIL

echo -n "Enter your Cloudflare API Key (e.g. 9a7806061c88ada191ed06f989cc3dac) and press [ENTER]: "
read KEY


echo -n "Enter path to create cf_ip_updater.sh script (e.g. /home/path) and press [ENTER]: "
read FILEPATH


#Get Zone and Record IDS
ZONEID=$(curl -X GET "https://api.cloudflare.com/client/v4/zones?name=$FULLDOMAIN" \
  -H "X-Auth-Email: $EMAIL" \
  -H "X-Auth-Key: $KEY" \
  -H "Content-Type: application/json" | jq . | grep id | head -1 | cut -d '"' -f4)

RECORDID=$(curl -X GET "https://api.cloudflare.com/client/v4/zones/$ZONEID/dns_records?name=$SUBDOMAIN" \
  -H "X-Auth-Email: $EMAIL" \
  -H "X-Auth-Key: $KEY" \
  -H "Content-Type: application/json" | jq . | grep id | head -1 | cut -d '"' -f4)


#Print IDS
echo "Your Zone ID:   $ZONEID"
echo "Your Record ID: $RECORDID"


#Create script
FILE="$FILEPATH/cf_ip_updater.sh"
echo "Your script name: $FILE"


cat <>$FILE
#!/bin/sh

[ ! -f /var/tmp/current_ip.txt ] && touch /var/tmp/currentip.txt

NEWIP=\$(dig +short myip.opendns.com @resolver1.opendns.com)
CURRENTIP=\$(cat /var/tmp/currentip.txt)

if [ "\$NEWIP" = "\$CURRENTIP" ]
then
  echo "IP address unchanged"
else
  curl -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONEID/dns_records/$RECORDID" \
    -H "X-Auth-Email: $EMAIL" \
    -H "X-Auth-Key: $KEY" \
    -H "Content-Type: application/json" \
    --data "{\"type\":\"A\",\"name\":\"$SUBDOMAIN\",\"content\":\"\$NEWIP\"}"
  echo \$NEWIP > /var/tmp/currentip.txt
fi
EOM

chmod +x $FILE
Limitations

If you run this file more than once, it appends to the bottom of the previous run for cf_ip_updater.sh . Otherwise, I guess it’s OK.

 

Resources and References
  • http://unix.stackexchange.com/questions/45781/shell-script-fails-syntax-error-unexpected
  • http://askubuntu.com/questions/186808/every-command-fails-with-command-not-found-after-changing-bash-profile
  • http://unix.stackexchange.com/questions/48392/understanding-backtick
  • http://stackoverflow.com/questions/11710552/useless-use-of-cat
  • http://stackoverflow.com/questions/7549404/bash-script-to-pass-variables-without-substitution-into-new-script
  • http://unix.stackexchange.com/questions/238881/how-do-i-append-multiple-lines-involving-variables-to-the-end-of-a-bash-script
  • http://unix.stackexchange.com/questions/331068/append-multiple-lines-specified-as-verbatim-bash-variable-after-a-matched-line
  • http://unix.stackexchange.com/questions/147082/how-to-append-multiple-lines-to-a-file-with-bash-with-in-front-of-string
  • http://stackoverflow.com/questions/7875540/how-do-you-write-multiple-line-configuration-file-using-bash-and-use-variables
  • http://unix.stackexchange.com/questions/77277/how-to-append-multiple-lines-to-a-file-with-bash
  • http://stackoverflow.com/questions/4181703/how-can-i-concatenate-string-variables-in-bash
  • http://unix.stackexchange.com/questions/94664/how-to-echo-variables-using-cat-into-file
  • http://www.tldp.org/LDP/abs/html/here-docs.html#HERELIT
  • http://stackoverflow.com/questions/11162406/open-and-write-data-on-text-file-by-bash-shell-scripting
  • http://stackoverflow.com/questions/4662938/create-text-file-and-fill-it-using-bash
  • http://stackoverflow.com/questions/8737638/assign-curl-output-to-variable-in-bash
  • http://stackoverflow.com/questions/25320928/how-to-capture-the-output-of-curl-to-variable-in-bash
  • http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-5.html
  • http://stackoverflow.com/questions/840536/how-to-use-environment-variable-inside-a-quoted-string-in-bash-script
  • http://unix.stackexchange.com/questions/148285/extract-value-between-double-quotes
  • http://unix.stackexchange.com/questions/166359/how-to-grep-the-output-of-curl

The following is an OpenVPN autologin script for my portable Raspberry Pi Kodi media center. It starts an OpenVPN connection on boot.

 

Dependencies

  • The Expect package
  • A folder containing an OpenVPN configuration file
  • A folder for the script (I put it in the same OpenVPN folder)

 

Script Creation

sudo apt-get install expect
sudo nano autovpnscript.sh
chmod +x autovpnscript.sh

 

Contents

#!/usr/bin/expect

set password "Password-For-OpenVPN-Connection\r"
set config "Path-To-OpenVPN-Config-File(*.ovpn)"

cd /Path-To-OpenVPN-Config-Folder

spawn openvpn $config
expect "Enter Private Key Password:"
send $password
#interact
expect eof
exit

 

Add to Crontab

sudo crontab -e
@reboot /Path-To-Script-Folder/autovpn.sh

 

Stop OpenVPN

sudo killall openvpn

 

 

References – 1, 2, 3, 4, 5, 6

 

 

 

 

I’m currently working on a project where I set up a Raspberry Pi to host a VPN server so that I can let my extended family view some private pictures. I previously had a PritUNL server running on Digital Ocean with a remote mLab MongoDB server, but it didn’t seem to work too well, with connections getting dropped and some serious compatibility issues. PritUNL does, however, have a very nice interface and supposedly better resource usage than OpenVPN Access Server, the limited-to-two-concurrent-users OpenVPN solution I was using before.

My current setup had a PritUNL client (running unknown in the background) and a SecurePoint client on Windows 10, with OpenVPN on my RPi set up through PiVPN. The SecurePoint client was very easy to use, and it worked when I ran it. After testing that it worked, I hibernated my PC and went to work. And that’s when things went wonky.

When I opened up my PC, I saw three WiFi networks, the SSIDs that are from my house. There’s no way those things would be available at work. No other network was available. I knew it had to be something to do with my VPN software, so I uninstalled those and rebooted.

The problem persisted. I looked online, and it showed me that Windows 10 used to have a bug where old, unsupported VPNs (Cisco) would cause some internet connection issues. So I ran the fix for that (using cmd.exe in admin mode):

reg delete HKCR\CLSID\{988248f3-a1ad-49bf-9170-676cbbc36ba3} /f

netcfg -v -u dni_dne

And the problem persisted. I searched some more and ran a number of ipconfig and netsh commands. Finally, I found this page from Microsoft with some handy netsh tools:

netsh wlab show wlanreport – creates a report of the current wlan setup/status accessible at C:\ProgramData\Microsoft\Windows\WlanReport

netsh -d – resets all network configurations and settings, but MS recommends it only as a last resort

Basically, netsh -d worked, but it also erased all my WiFi profiles. I played around with netsh some more, and I learned you can export current profiles using this command: netsh wlan export profile folder=c:\WifiProfiles\, which sends the profiles to C:\WifiProfiles. It’s not very intuitive, or maybe because I only had one profile, but it would seem that netsh wlan export profile name="George's iPhone" folder=c:\WifiProfiles\ should have worked, but it sends me this error: Profile "George's iPhone" is not found on any interface.

Once you backup your profiles like this, you can probably use netsh wlan add profile filename="ProfileName.xml" interface="Wireless Network Connection" user=current to import profiles that have been erased. I didn’t try it because I didn’t have any profiles backed up.

Then I downloaded OpenVPN and didn’t know how to get it to connect, which actually requires you to put the ovpn profile into the C:\Program Files\OpenVPN\config folder, and then right clicking the system tray GUI to get the Connect option to appear. Without the ovpn profile, the Connect option doesn’t pop up.

Anyway, that’s three things learned today: netsh wlab show wlanreport, netsh -d, and OpenVPN config folder. And although PiVPN doesn’t support bridging, I can access all the network drives and printers that I need to.

Interesting.

 

 

Photo by Nguyen Vu Hung (vuhung)