<Guide> Enabling OpenVPN/iptables combo in Custom Firmware

The main reason I got this NAS is that it wasn’t too expensive and the full GPL source code was available. This is because I want to set up an OpenVPN server on my NAS which can route my internet connection. For this I need Iptables and OpenVPN. This tutorial is my notes on getting it all working on the EX2

WARNING: Usual disclaimer, Custom Firmware VOIDs your WD warranty. If you brick your NAS as a result of these instructions, don’t come crying to me, I won’t have any sympathy, nor do I bare any responsibility for any loss of data, hardware, anything, as a result of, or indirectly related to following these instructions. You are soley responsible for what happens next!

Ok, so, the release notes are mostly useless in trying to explain the process of building the firmware, so here goes some more explanatory notes. These are based on looking at the release notes for 4 different versions of the firmware and then lots of experimentation. WD seem to remove information from the ReadMe’s as each release goes on. But anyway…

Firstly you will need the source code from the WD website (Here at time of writing: http://support.wdc.com/product/download.asp?groupid=906&sid=220&lang=en))
The latest GPL Source at the time I wrote this is 1.05.30_20141210, so I am basing my instructions on that.

I am using Ubuntu 14.04LTS x86_64 as a build environment as that is what I have installed - given that I have a Windows 8 Laptop with UEFI and what-not, 14.04 is what I had to use to get any form of Linux installed at the time :wink:

PART 1 - Getting Ready

(1a) On your build machine (not the NAS), download the source code.

( b) In Terminal, log in as root

sudo su

( c) Extract the files using:

tar zxvf WDMyCloud_EX2_GPL_v1.05.25_20141110.tar.gz

I then renamed the directory to WDMyCloud, but isn’t really neessary, just reduced the length of the terminal prompt :wink:

mv WDMyCloud_EX2_GPL_v1.05.25_20141110/ WDMyCloud/

( d) Change to the directory

cd WDMyCloud

( e) Set the HOME_DIR variable to the current directory (it is used by the tools to find the root folder).

export HOME_DIR=`pwd`

( f) Next we need to extract the build toolchain. This is supplied as part of the download and is located in the $HOME_DIR/toolchain folder.

cd $HOME_DIR/toolchain
tar zxvf armv7-marvell-linux-gnueabi-softfp_i686_64K_Dev_20131002.tar.gz

IMPORTANT NOTE: If while doing the next steps you come across any script which won’t execute (e.g. xBuild.sh), don’t even consider trying to manually change the file permissions. This happened to me once and little did I know it was because all of the file permissions had been accidentally lost when I extracted the firmware. This meant the ENTIRE file system in the firmware had been marked as read-only and non-executable and it bricked my NAS. If you come across the same permissions issue, STOP IMMEDIATELY, and reextract the firmware making sure to keep file permissions! 

  

PART 2 - Preparing the Kernel

(2a) First step is to extract the kernel source code which is included with the download.

cd $HOME_DIR/kernel
tar zxvf linux-3.2.40.tar.gz

( b) Now set up the environment to cross compile using the supplied toolchain. Fortunately this is one thing WD made easy as they included a setup file.

source source.me

( c) And move into the kernel source directory

cd linux-3.2.40

( d) Do a build of the kernel to make sure everything is working (correct toolchain is being used, etc.)

./xbuild.sh build

Hopefully the build will work - for me it worked without any faffing around, so if it doesn’t work for you, make sure you followed the above steps carefully. The build took about 5 minutes on my computer - a few warnings from various modules, but that seems to be par for the course for this sort of thing.

( e) The next part is customising the modules you want. The xBuild.sh file doesn’t have an option for this, but it is not needed, just run

make menuconfig

( f) This should load a grey box on a blue background which is titled “.config - Linux/arm 3.2.40 Kernel Configuration”. Using this wizard we can select which packages we need. For OpenVPN network bridging, we need IPTABLES with NAT capability which is the purpose of this build. So lets go ahead and select all the required packages.

I couldn’t find anywhere a complete list of exactly which packages were required. There were some which were obviously required, so I selected those, but I also selected some others just in case - save having the build it over and over again. If someone wants to let me know which options aren’t required, I will remove them from the list. Some of the options were enabled by default, so didn’t change those.

Networking Support -->
    Networking Options -->
        <*> advanced router
        <*> Netfilter --> (select this then enter the submenu)
            Practically everything in Netfilter except debugging and IPV6 - you can include IPV6 if you want, but I didn't. Remember to enter submenu's after select things indicated by a --> in menuconfig
        <*> L2TP

I also selected to include the kernel config in /proc, as I thought it may prove useful in debugging.
General Setup →

[*] Kernel .config support

  
#######################################################
I also have the following as I thought I might find them useful, but they are not needed for iptables/OpenVPN

Networking Support -->
    Wireless
Device Drivers -->
    Network Device Support -->
        Wireless LAN
    USB Support -->
        USB Modem
        USB Printer Support
    Filesystems -->
        Misc Filesystems -->
        Squashfs4 include LZO and ZLIB

#######################################################’

( h) Now escape back up to the top of the menu and go to the Exit button. Press Enter, then select yes to save changes.

( i) Rebuild the kernel using the same command as earlier:

./xbuild.sh build

Fingers crossed the build will go OK, and with a bit of luck in a couple of minutes you should have the kernel compiled with netfilter support.

( j) once done, copy the compiled kernel into the merge folder:

cp -f arch/arm/boot/uImage $HOME_DIR/firmware/merge/

( k) finally, copy all the the driver modules that were produced into the crfs driver modules folder:

find . -name '*.ko' -exec cp -afv \{\} $HOME_DIR/firmware/module/crfs/driver \;

  

PART 3 - Compiling iptables

Now that we have kernel support for iptables, we also need to build its binary files and included them in the root filesystem so we can use them.

I am also going to include the ‘nano’ text editor because I am fed up of only having ‘vi’. Lets start with that.

Unless you are familiar with using ‘vi’, Don’t skip building nano as I will be using it later when setting up OpenVPN.

(3a) First set up our environment for building the open source packages. Move to the open source packages directory and source the source.me file like we did for the kernel.

cd $HOME_DIR/Open_Source_packages/
source source.me

( b) To build nano, we are going to need the nano source files, so lets grab them

wget http://ftp.gnu.org/gnu/nano/nano-2.3.6.tar.gz
tar -xzf nano-2.3.6.tar.gz

( c) now that we have the nano source, we need to make a xbuild script for it.

cd nano-2.3.6
echo "" > xbuild.sh
chmod +x xbuild.sh
nano xbuild.sh

Add the following lines to the file, then save and exit.

#!/bin/bash

unset CFLAGS
unset LDFLAGS
unset LIBS

source ../xcp.sh
MY_PREFIX=$PWD/../_xinstall/${PROJECT_NAME}

xbuild()
{
    XINSTDIR=$(readlink -f ../_xinstall/${PROJECT_NAME})

    if [! -e ${XINSTDIR}/include/ncurses]; then
        echo "ERROR: You should build ncurses first"
        exit 1
    fi

    export CFLAGS="${CFLAGS} -I${MY_PREFIX}/include -I${MY_PREFIX}/include/ncurses"
    export CPPFLAGS="${CFLAGS} -I${MY_PREFIX}/include -I${MY_PREFIX}/include/ncurses"
    export LDFLAGS="${LDFLAGS} -L${MY_PREFIX}/lib"
    ./configure --host=${TARGET_HOST}

    make clean
    make
}

xinstall()
{
    echo "install"
    ${CROSS_COMPILE}strip -s ./src/nano

    xcp ./src/nano ${ROOT_FS}/bin/
}

xclean()
{
    make clean
}


if ["$1" = "build"]; then
   xbuild
elif ["$1" = "install"]; then
   xinstall
elif ["$1" = "clean"]; then
   xclean
else
   echo "Usage : [xbuild.sh build] or [xbuild.sh install] or [xbuild.sh clean]"
fi

( d) Now we hit a minor snag. In order to build nano, we need the curses library to link with. Fortunately the source for this is already included with the EX2’s GPL source code. Lets make it:

cd ..
tar -xzf ncurses-5.7.tar.gz
cd ncurses-5.7
./xbuild.sh build
./xbuild.sh install

That should progress smoothly and will build the curses library for us to link nano against.

( e) Now lets build and install nano :slight_smile:

cd ../nano-2.3.6
./xbuild.sh build
./xbuild.sh install

( f) Ok then, next up, lets build the iptables. First fetch its source code and extract it:

cd $HOME_DIR/Open_Source_packages/
wget http://www.netfilter.org/projects/iptables/files/iptables-1.4.21.tar.bz2
tar -xf iptables-1.4.21.tar.bz2

( g) Now once again we need to add an xbuild script:

cd iptables-1.4.21
echo "" > xbuild.sh
chmod +x xbuild.sh
nano xbuild.sh

Add the following lines into the xbuild.sh file, then save it and close nano.

#!/bin/bash

unset CFLAGS
unset LDFLAGS
unset LIBS

source ../xcp.sh
MY_PREFIX=$PWD/../_xinstall/${PROJECT_NAME}

xbuild()
{
    XINSTDIR=$(readlink -f ../_xinstall/${PROJECT_NAME})

    export CFLAGS="${CFLAGS} -I${MY_PREFIX}/include"
    export CPPFLAGS="${CFLAGS} -I${MY_PREFIX}/include"
    export LDFLAGS="${LDFLAGS} -L${MY_PREFIX}/lib"
    ./configure --host=${TARGET_HOST} --prefix=

    make clean
    make
}

xinstall()
{
    echo "install"
    make install DESTDIR=${ROOT_FS}
}

xclean()
{
    make clean
}


if ["$1" = "build"]; then
    xbuild
elif ["$1" = "install"]; then
    xinstall
elif ["$1" = "clean"]; then
    xclean
else
    echo "Usage : [xbuild.sh build] or [xbuild.sh install] or [xbuild.sh clean]"
fi

( h) Now build and install iptables

./xbuild.sh build
./xbuild.sh install

PART 4 - Building the Firmware

The next step is the build the firmware for uploading the the My Cloud EX2.
(4a) First, we need to build the root file system. So, change to the ramdisk directory:

cd $HOME_DIR/firmware/ramdisk

( b) We also need to make sure the pax command is available by installing the pax package:

apt-get install pax

   

( c) Now run the build script

./create_ramdisk.sh

( d) This should produce a new uRamdisk file in the ramdisk directory. This needs to be copied to the merge folder:

cp -f uRamdisk $HOME_DIR/firmware/merge/

( e) Next we need to pack in all the precompiled binaries from WD and all of the driver modules build earlier. These are located in the module folder.

cd $HOME_DIR/firmware/module

( f) Now we should make sure there are no old images lying around, and then create the new one:

rm my-image.cfs
./create_image.sh

( g) This should complete after a minute or so. Once done, copy the output to the merge folder as well:

cp -f my-image.cfs $HOME_DIR/firmware/merge/image.cfs

( h) Finally, lets build our custom firmware. First move into the merge directory where all of the parts of our firmware should now be located:

cd $HOME_DIR/firmware/merge

There should be at least the following files in this folder (run ls to see):

default.tar.gz image.cfs
merge
uImage
uP.bin
uRamdisk

( i) Next run the merge tool.

./merge

( j) And that is it, you should now find that the firmware file has been created.

ls

Should reveal a file called “WD-NAS-firmware” has been created.

( l) Lets just move it to your user area and adjust its file ownership so you have access.

cp WD-NAS-firmware /home/yourUsername/Desktop/
chown yourUsername:yourUsername /home/yourUsername/Desktop/WD-NAS-firmware

( m) And finally it is time to leave your root console.

exit

Now you just have to upload the new firmware using the web utility, and hope to **bleep** that you don’t brick your EX2!!

4 Likes

PART 5 - Setting Up OpenVPN

Now that the firmware is updated, we just need to set up OpenVPN. Now the way I am doing this doesn’t actually start automatically, we have to do it manually. Part of the problem is that the operating system is overwritten from the flash every time we boot, so if we change any startup scripts it won’t be permanent. The only way to do it permanently would as far as I know be to recompile the firmware. If someone knows a better way, please, let me know!
The good news is there is a section of the OS which is not lost, the /usr/local/config/ directory. So this is where I am going to set up all the OpenVPN configuration.
(5a) Start by making a directory in the config folder and moving there:

mkdir /usr/local/config/openvpn
cd /usr/local/config/openvpn

( b) The OpenVPN version on the NAS is fine, but it doesn’t come with any of the example scripts or easy-rsa. So first lets get easy-rsa:

wget --no-check-certificate https://github.com/OpenVPN/easy-rsa/archive/release/2.x.zip

( c) Extract only the folder we need, then clean up the rest

unzip 2.x
mv easy-rsa-release-2.x/easy-rsa/2.0 ./easy-rsa
rm 2.x
rm -R easy-rsa-release-2.x

( d) Now lets configure easy-rsa. Good thing we installed Nano, otherwise you would have to do this with vi!

nano vars

Edit the following lines (they are near the bottom of the file) to whatever details you want on your CA (pick something you can identify as you):

export KEY_COUNTRY="Country"
export KEY_PROVINCE="State/Province"
export KEY_CITY="City"
export KEY_ORG="Organisation"
export KEY_EMAIL="an@email.address"

( e) Next lets create our certificates. In the below commands, replace with whatever you want your OpenVPN server to be called:

source vars
./clean-all
./build-dh
./pkitool --initca
./pkitool --server <ServerName>
cd keys
openvpn.bin --genkey --secret ta.key

( f) Now move our keys to the openvpn folder. Again, replace with whatever you used above.

cp <ServerName>.crt <ServerName>.key ca.crt dh2048.pem ta.key /usr/local/config/openvpn

( g) Now we make some client keys. Replace with the name of your client. Do this for each of the clients you want to connect:

cd /usr/local/config/openvpn/easy-rsa
source vars
./pkitool <ClientName>

( h) Now lets put the keys we need to give to the client into an archive, and copy it somewhere where we can access it - e.g. into the shares/yourName folder. Again replace as above. Also replace with the name of your share on the NAS.

tar -czf keysForClient.tgz ca.crt ta.key <ClientName>.crt <ClientName>.key
mv keysForClient.tgz /shares/<yourName>/

For the following scripts I am assuming that the IP address of your VPN is 10.10.10.0 to 10.10.10.24. If you have a different address or range, make sure to change the IP addresses in the below script.
I am also using a TAP interface with TCP. I’ve configured my router to port forward the TCP port that I am using to my NAS which I have made the router assign a static IP to.

( i) Now we create a script for configuring iptables when when load the VPN.

cd /usr/local/config/openvpn
echo "" > up.sh
chmod 755 up.sh
nano up.sh

    
Then paste the following into that file:

#!/bin/bash
#This is /etc/openvpn/up.sh

IPT="/usr/sbin/iptables"
LAN="egiga0"
VNET="10.10.10.0/24" #VPN network IP Range
VPNIF="tap+"

sysctl -w net.ipv4.ip_forward=1

#Flush existing rules
$IPT -P INPUT ACCEPT
$IPT -F INPUT
$IPT -F OUTPUT
$IPT -F FORWARD
$IPT -t nat -F

#And set up some new ones
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT
$IPT -A INPUT -i $VPNIF -j ACCEPT
$IPT -A FORWARD -i $VPNIF -j ACCEPT
$IPT -t nat -A POSTROUTING -s $VNET -o $LAN -j MASQUERADE

Save and exit nano.

( j) Now create a server.conf file to run:

echo "" > server.conf
chmod 755 server.conf
nano server.conf

    
And then paste in the following, making changes as required

# Static IP of your NAS
local 192.168.1.10

# Which TCP/UDP port should OpenVPN listen on?
port 1194

proto tcp

dev tap

script-security 2
up "/usr/local/config/openvpn/up.sh"

# Make sure you change the <ServerName> below to whatever you called your server.
ca /usr/local/config/openvpn/ca.crt
cert /usr/local/config/openvpn/<ServerName>.crt
key /usr/local/config/openvpn/<ServerName>.key

dh /usr/local/config/openvpn/dh2048.pem

topology subnet

# Make sure to change the IP to match your desired VPN and what is in up.sh
server 10.10.10.0 255.255.255.0
ifconfig 10.10.10.1 255.255.255.0

ifconfig-pool-persist ipp.txt

# Make sure you change the IP below to match your local network and VPN ip's 
push "route 192.168.1.0 255.255.255.0 10.10.10.1"

# Redirect Gateway so we can have internet through the VPN
push "redirect-gateway def1"

# Update these to your ISP's DNS servers, or leave them as the google public DNS.
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 8.8.4.4"

# Uncomment this directive to allow different
# clients to be able to "see" each other.
# By default, clients will only see the server.
# To force clients to only see the server, you
# will also need to appropriately firewall the
# server's TUN/TAP interface.
client-to-client

# The keepalive directive causes ping-like
# messages to be sent back and forth over
# the link so that each side knows when
# the other side has gone down.
# Ping every 10 seconds, assume that remote
# peer is down if no ping received during
# a 120 second time period.
keepalive 10 120

tls-auth /usr/local/config/openvpn/ta.key 0 # This file is secret

comp-lzo

# The maximum number of concurrently connected
# clients we want to allow.
max-clients 24

persist-key
persist-tun

status openvpn-status.log

verb 4

Save and exit nano.

( k) Finally, start OpenVPN:

cd /
openvpn.bin --config /usr/local/config/openvpn/server.conf &

Now all you need to do is set up your OpenVPN client using the keys that you saved to /shares/<yourName>/keysForClient.tgz, which you can copy from the Nas at your convenience.

Fingers crossed you will now have a working VPN. If anyone has suggestions or corrections, I am all ears.

4 Likes

Thanks very much for the write-ups TCWORLD.

On your 5th section about setting up OpenVPN, the issue you mentioned about being unable to permanently save changes because the OS gets refreshed from the flash everytime on reboot, is the part that I can definitely help you with (hopefully I understood your issue correctly). In fact, everything that I have done in the past year in my custom compiled firmware, has been primarily to bake-in all my custom scripts and other custom config files into the firmware, before I compiled it.

So the three things that you need to know are:

  1. you can put all your custom shell scripts along with other shells scripts in /path_to_extracted_source/WDMyCloud_EX2_GPL_vXX/module/crfs/scripts

  2. the startup script is system_init in that directory. If you want to add/modify behavior during startup, just edit that (invoking any custom scripts where needed)

  3. most of the config files that are pulled into /etc/ come from one file default.tar.gz inside /firmware/merge directory (although I am running a couple firmware versions behind and don’t see that mentioned in your list of files in the merge directory when you compile the firmware so I am not sure if WD changed things up a bit in last couple most recent firmware versions and removed it from there and put it elsewhere). Inside this tarball is the very important config.xml (among other default config files), where you can hardcode any config changes you like and it then gets copied to /usr/local/config/config.xml during firmware upgrade and then on each subsequent reboot /usr/local/config/config.xml gets copied to /etc/NAS_CFG/config.xml. Any changes you make to config via the dashboard like say ftp configs, etc. gets saved to the /usr/local/config/config.xml

Those 3 places where I have a lot (but not all) of my changes located. I do have a few other places where I updated things And yes, I too have been using the /usr/local/config directory to store my custom configs to preserve between reboots :slight_smile:

Once you compile the firmware, that script directory (/module/crfs/scripts) will be located at /usr/local/modules/scripts/ on the NAS.

Hope this helps. Feel free to PM me if you have any questions.

You’re right, there is a default.tar.gz in the merge folder. I’d forgotten about that. Interestingly WD don’t mention it in the README with the firmware.

TCWORLD wrote:

You’re right, there is a default.tar.gz in the merge folder. I’d forgotten about that. Interestingly WD don’t mention it in the README with the firmware.

Of course they wouldn’t…that’s what intrepid modders/DIYers like you and me are here for :) To poke and prod and discover all the undocumented stuff.

I appreciate your contributions.

Hi,

Thanks for your valuable description. However, I have a problem. Can you guide me how you write xbuild.sh files? I checked most of the files but it looks to me they are all different. How can I know which one is correct if I want to add something?

Thanks in advance,

Mehmet 

Dear TCWorld,
is there have simple method to install openvpn server on EX2Ultra?
like provide third party binary app or else.

I installed docker and try to mount openvpn server on it but fail.
so sad WD can 't support OpenVPN Server feature for EX2Ultra.

Anyone know if this still works now that we’re on 5.18?

I can’t even get Ubuntu to see the source code… This is such a simple setting that WD should already have implemented.