Oct 282009

UPDATE!! 2015-02-02

The OpenConnect project, which was initially created to support Cisco’s AnyConnect has brought in support for Juniper VPN’s. While I haven’t tried it myself (no access to a Juniper VPN any longer) it could be a huge time saver.
Be sure to check it out at: http://www.infradead.org/openconnect/

UPDATE!! 2011-09-02

A recent post at ubuntuforums.org demonstrates a much easier way to log into a Juniper VPN with 64 bit Linux. I suggest trying this method before reading ANY MORE of this article.* Direct link: http://ubuntuforums.org/showthread.php?p=11189826#post11189826

Thank you Eccentric.Ash for bringing this to my attention in the comments. The approach in the linked forum post is much much easier to implement. And a special shout out to dvo over at ubuntuforums.org for sharing this solution.

Useful script: I received an email from a nice fellow, also named Scott, who produced some code to automate this process a bit. With his permission I am sharing the link to his Google Code project here: juniper-vpn.

I’ve been running the 32-bit version Linux Mint 7 for the past month. To date it’s been the most straight forward “everything just works” Linux distribution that I’ve used. And it wasn’t ugly either. But, not quite everything “just works” the way it should. Pulseaudio and the ALSA sound driver for snd-hda-intel just didn’t work very well.

One thing that I was really shocked to see working perfectly, without any intervention on my part was the SSL VPN client from Juniper. It just worked and it worked very well

B+ for Linux Mint and A+ for Juniper. Good job folks!

Er, not so fast. 32-bit Linux is getting kind of dated. My machine is a Core2 Duo, 64-bit, so it’s kinda silly not to take advantage of that. And to top it off, Unbuntu 9.10 Beta was just released.

I installed it. It went quite well. I installed it right over the Windows XP partition I had been saving for absolutely no sensible reason. Later Windows!

Then I tried to log into the VPN.

It did nothing.

I felt sad.

So I put on my hacker hat and started digging. Starting, of course, with a Google search that turned me onto a nice solution that some other gentleman had worked out. Unfortunately it wasn’t quite enough. We use a two-phase auth scheme and this only supports a one phase. We need a username, password, and RSA token. This script assumes you only use a PIN+RSA token as a single password. The fortunate part is that his script really identified all of the key pieces so I could eventually solve the puzzle. But it wasn’t as obvious as it should have been.

Here’s how the Juniper SSL VPN client works (for Linux):

  1. Log into a secure web site
  2. Click the Start button for the SSL VPN client
  1. This launches a Java applet that in turn launches a Java webstart app
  2. Downloads some files (into $HOME/.juniper_networks directory)
  3. Explodes a jar file (into $HOME/.juniper_networks/network_connect)
  4. Checks for the tun device
  5. Extracts the actual VPN client software
  6. Prompts you for superuser password
  7. chowns root:root the VPN client software
  8. chmods 4775’s the VPN client software
  9. Runs the VPN client software, communicating with the Java app via IPC. It’s … fascinating.

In a 32-bit Linux system this works wonderfully well. It’ll also auto update which is very cool.

In a 64-bit Linux system not so much. It pretty much just chokes when the dynamic linker tries to pull in a file called libncui.so, which happens to be a 32-bit ELF binary.

But the show doesn’t end here. The application is still present in $HOME/.juniper_networks/network_connect.

By now you are either very bored or you are thinking, well hey, why not just run the application and give the DSID! If so, then you are pretty much on the same page as I was at the time. But get this. There is *no* way, to my knowledge, to give that stinking DSID to that stinking ncsvc application without jumping through the same IPC hoops as the Java app. Well, I’m not about to try and debug *that*. No thank you!

But wait a minute… Doesn’t the Mad Scientist’s script mentioned above work? It must be providing that DSID right? Not quite. The ncsvc application actually does provide some command line switches that are really useful. Here’s what the usage string looks like:

usage: ./ncsvc -h host -u user -p passwd -r realm -f cert_file [-L log_level] [-g] [-U sign_in_url]
       ./ncsvc -v
       ./ncsvc -K

    log_level : 0 : Log Critical messages only
                1 : Log Critital and Error messages
                2 : Log Critital, Error and Warning messages
                3 : Log Critital, Error, Warning and Info messages(default)
                4 : Log All Verbose messages
                5 : Log All messages
    -v : Print version information and quit
    -g : Zip and upload logs to host
    -K : Kill all running ncsvc services

Notice, there is a -p for password? That’s great, but we need two passwords in a two phase auth scheme. There isn’t  a -pp or a –second-password or any other such switch. There just isn’t any bloody way to suff that 2nd password down its throat.

At this point it’s time to start digging through all of the files that are included with the VPN app. There is more to it than just ncsvc. Quite a bit more. Here is the listing:

  • installnc.log
  • missing.info
  • ncsvc
  • version.txt
  • NC.jar
  • installNC.sh
  • libncui.so
  • ncdiag
  • xlaunchNC.sh

Some shell scripts that prove mostly useless and a couple of logs containing anything but useful information.

The files that look interesting are ncsvc (obviously), NC.jar, ncdiag, and libncui.so.

At this point I hadn’t a clue where to look so I started with the NC.jar file. I figure I could jar xf it, javap all of the class files and see if they led me down any interesting paths, I could try to run it withjava -jar NC.jar … Aha! More command line switches, and they look like this:

usage: ncui -h host -u user -p passwd -r realm -f cert_file [-l log_level] [-L log_level]
       ncui -h host -c cookies -f cert_file [-l log_level] [-L log_level] [-U sign_in_url]
       ncui -v
    log_level : 0 : Log Critical messages only
                1 : Log Critital and Error messages
                2 : Log Critital, Error and Warning messages
                3 : Log Critital, Error, Warning and Info messages(default)
                4 : Log All Verbose messages
                5 : Log All messages

Yep, typo’s and all. “Critital” haha… Nice. But isn’t that -c option looking pretty tasty? Yessss! Let’s give it a shot…

bash$ java -jar NC.jar -h myhost -c DSID=nnnnn... -f ssl.crtInvalid parameter -c

Major let down. MAJOR let down. I spent a good while trying to get that parameter accepted. My perseverance finally paid off when a quick strings * revealed the true source of that usage string that NC.jar spewed forth. It was in libncui.so. Now what kind of shared object file has a usage string inside?

DING DING DING! We have a winner!

With little fanfare I continued my hacking until I finally came up with the solution:

  1. Install gcc-multilib for 32bit compiler/linker support
        apt-get install gcc-multilib
  2. Build an executable from libncui.so and call it ncui.
        gcc -m32 -Wl,-rpath,`pwd` -o ncui libncui.so
  3. Chown and chmod that executable to be suid root
        sudo chown root:root ncui
        sudo chmod 4755 ncui
  4. Run it with the same parameters we used when running NC.jar
        ./ncui -h myhost -c DSID=nnnnn... -f ssl.crt

The cursor just blinked at me.

It didn’t fail.

There wasn’t an error message.

Did it work?

Yes! Glorious success! It worked! A quick run of netstat -nr revealed that all of the VPN specific routes were present, I could resolve names, and I could ping the resolved IP addresses. I could access services. Everything looked just a little brighter.

In total I probably spent about 12 hours of my weekend painfully going through all of the motions to finally get to a working VPN client. Next I’ll spend a few hours writing up some dandy ruby code that logs me into the VPN from the command line. No more web browser. Not necessary.

In summary, if you are looking for the final solution it goes exactly like this:


  • gcc-multilib installed
        sudo apt-get install gcc-multilib
  • parital install of network connect in $HOME/.juniper_networks/network_connect
        libncui.so ncsvc

First time:

  1. Build your ncui executable:
        cd $HOME/.juniper_networks/network_connect
        gcc -m32 -Wl,-rpath,`pwd` -o ncui libncui.so
  2. Get your HOST SSL certiciate:
        echo |
          openssl s_client -connect (your host):443 2>&1 |
          sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' |
          openssl x509 -outform der > ssl.crt

Every time:

  1. Log into your VPN web site normally and fetch the DSID cookie. In your browsers location bar enter:
  2. Run the VPN client
        cd $HOME/.juniper_networks/network_connect
        ./ncui -h <your host>\
               -c <your cookie>\
               -f ssl.crt
  3. If prompted for a password just press ENTER.
  4. Enjoy the fruits of your labor!
 Posted by at 4:00 am

  38 Responses to “Juniper VPN, 64-bit Linux .. an unsolved mystery?”

  1. I have been struggling with this for a while now (Ubuntu 10.04 LTS, AMD 64), even with a setup that is less complicated as yours ( a single password).

    Your solution works perfectly !
    Thanks a lot.


    • I’ve been toying with this for what seems like forever. This seems to work perfectly in archlinux 64-bit.

      Nice work!

  2. Yess! This is the best thing ever! One remark though: enter the cookie with ‘DSID=’ in front of it. Took me a few extra minutes before I had that figured out.

    Like in:

    ./ncui -h vpnbox.example.com -c DSID=63b5fb409b07e0ee2e6572b163d75142 -f ./ssl.crt

  3. Great post! It was really helpful for me! THANKS A LOT!

    Good remark from Marco D, about DSID!

  4. Scott, your method worked perfectly for me until my company decided to upgrade to “Junos Pulse Secure Access Service”. That upgrade broke the workaround that you had suggested above.

    After about a week of trying in vain, I came across the below post on Ubuntu Forums that is a simple fix for the problem. I hope this helps others who are in the same boat as me.


    • I’ll link it in the TOP of the article. It’s so much simpler! I do tend to do things the hard way.

      Thank you sooooo much for posting the link here!

  5. Here is a simple solution for the Juniper NC 64-bit incompatibility problem, which works even with smart card authentication:

    • David, thanks for solving this more easily. I’ve posted a direct link to your post at ubuntuforums.org at the top of this article. It’ll save a lot of people a lot of time.

    • YES!!!!! Awesome…..thank you thank you thank you…..my maverick is smiling again…..:)

      • I type this cmanomd “ip addr show” and got below output1: lo: mtu 16436 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet scope host lo inet6 ::1/128 scope host valid_lft forever preferred_lft forever2: dummy0: mtu 1500 qdisc noop state DOWN link/ether ca:ba:69:31:2e:6c brd ff:ff:ff:ff:ff:ff3: usb0: mtu 1500 qdisc noop state DOWN qlen 1000 link/ether 76:f0:b1:17:79:13 brd ff:ff:ff:ff:ff:ff4: eth0: mtu 1500 qdisc noop state DOWN qlen 1000 link/ether 00:a0:c6:00:00:00 brd ff:ff:ff:ff:ff:ff5: sit0: mtu 1480 qdisc noop state DOWN link/sit brd ip6tnl0: mtu 1460 qdisc noop state DOWN link/tunnel6 :: brd ::7: wlan0: mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 40:fc:89:27:41:c5 brd ff:ff:ff:ff:ff:ff inet brd scope global wlan0 inet6 fe80::42fc:89ff:fe27:41c5/64 scope link valid_lft forever preferred_lft forever9: tun0: mtu 1500 qdisc noop state DOWN qlen 500 link/none

  6. Excellent solution! Congratulations, really works. Thanks a lot.

  7. Thanks!

  8. When I ran
    gcc -m32 -Wl,-rpath,`pwd` -o ncui libncui.so
    I got this error

    gcc -m32 -Wl,-rpath,`pwd` -o ncui libncui.so
    /usr/bin/ld: warning: libz.so.1, needed by libncui.so, not found (try using -rpath or -rpath-link)
    libncui.so: undefined reference to `inflateReset'
    libncui.so: undefined reference to `inflateEnd'
    libncui.so: undefined reference to `deflate'
    libncui.so: undefined reference to `inflateInit2_'
    libncui.so: undefined reference to `inflate'
    libncui.so: undefined reference to `compress2'
    libncui.so: undefined reference to `deflateEnd'
    libncui.so: undefined reference to `deflateInit2_'
    libncui.so: undefined reference to `uncompress'
    collect2: ld returned 1 exit status

    I had to install libz using
    sudo apt-get install lib32z1

    After this I was able to create ncui

  9. Got the same error as rahul on my arch linux. I had to install lib32-zlib :
    sudo pacman -S lib32-zlib

  10. I’m using arch-linux and needed to enable packetforwarding :
    in /etc/sysctl.conf
    I also did the following, don’t know if this really is necessary :
    in /etc/rc.local :
    ip link set dev eth0 promisc on

  11. I’m on Fedora 16, 64x and have the same problem,I found this problem is java64 attempting to load a 32b DLL. of course this fails..

    java.lang.UnsatisfiedLinkError: /path/.juniper_networks/network_connect/libncui.so: /path/libncui.so: wrong ELF class: ELFCLASS32 (Possible cause: architecture word width mismatch)

    meaning that until juniper wont recompile the ELF for 64b it wont work.. beh… (so you need to hack your browser to use java32 instead)

  12. Great Job !
    It works Perfectly !!
    (the dsid took me more time than anything else !)

    Thanks again !

  13. GREAT !!!!
    Been struggling with this for like ages before I found your excellent instructions.
    Thank you

  14. […] at makefile.com deserves a lot of credit for teasing the ncui command out for the jar files shipped by […]

  15. Hi,

    Thanks for your post, it was really useful. I can now connect to our VPN. This post was clear and concise and finally, I can connect without having to downgrade my entire system to 32-bit.


  16. Hi, did similiar hack but in more secure way, without exposing DSID in command arguments. See https://github.com/samm-git/jvpn/blob/master/wrapper.c and http://smallhacks.wordpress.com/tag/jvpn/

  17. […]I even came across an excellent tutorial for using network connect in an entirely non-gui way at this link:

    many props to scott for being a genius[…]

  18. Thank you sooooooooo much!!!!!

  19. Thank you very much. It works on ubuntu 13.04 amd64. It made my day!

    ./ncui -h webvpn.nus.edu.sg -c DSID=217f78c497e6731b0895daa130fbdaac -f ssl.crt

  20. […] post by Scott in 2011 has explained in great details how to connect to Juniper VPN from 64-bit linux. It […]

  21. Absolutely awesome work! Thanks a lot!

  22. Hey Scott,

    That was pretty neat! I tried the same based on your instructions and they work fine. However I am experiencing network interface issues after killing the ncui process.

    To reproduce:
    1. Run ncui: ./ncui -h vpn.site.com -c DSID=cookie -f ssl.crt
    2. tun0 comes up, vpn connectivity is fine
    3. Kill ncui process that is running (using Ctrl + c)
    4. tun0 goes down (as vpn is killed)
    5. Now, Cannot ping anything, restarting the network doesn’t work

    I need to either restart the machine or manually turn the interface down and up again on encountering this issue. I don’t want the users to face this interface issue after killing the VPN connection. Any suggestions or recommendations for resolving this issue?

    Thank you, Scott!

    • The only thing I can think of is that the routing tables got screwed up after closing the VPN connection. You might just have to do something like restart the networking service.

  23. HI,

    Every time a have to get the cookie DSID ?
    Is there another way?? because if every time i should do this is easier log in normally.


  24. I love you, man! You’re my hero! 😀

  25. […] (SecurID + AD password), it can get more involved. Scott has GREAT blog on how to make it work: http://makefile.com/.plan/2009/10/juniper-vpn-64-bit-linux-an-unsolved-mystery Only thing – you have to copy DSID cookie manually and paste it as argument in ncui call.  […]

  26. Hi,

    I am using fedora 20 64 bit and it is not working. it is not the same way like u can do it on ubuntu. can any one please help me.

  27. Solved. Do the following to allow Host Checker and Network Connect to load and connect using a 64 bit Linux environment and Firefox:

    Prepare a 64-bit Linux Machine 14.04 LTS NO HACKS NECESSARY

    Remember, the role must NOT be configured to use Junos Pulse, only Network Connect.

    1. Using a terminal session, make java directory for both 32 and 64 bit environments:
    a. sudo mkdir -p /usr/lib/jvm/java32
    b. sudo mkdir -p /usr/lib/jvm/java64
    2. The directories may differ but for consistency, continue to use the above directory structure
    3. Download java from http://java.com/en/download/manual.jsp and extract into your Download folder for both 32 and 64 bit environments. The download file names are identical. Either rename the tar file or place in a separate directory under the download folder. The next step uses different directories when downloading files. The tar files were downloaded and extracted to their respective download folders.
    4. Move extracted contents to the directories created in step 1.
    a. sudo mv /home/(username)/Downloads/jre1.8.0_25-32/* /usr/lib/jvm/java32
    b. sudo mv /home/(username)/Downloads/jre1.8.0_25-64/* /usr/lib/jvm/java64
    5. Make the Mozilla plug-in directory:
    a. sudo mkdir ~/.mozilla/plugins
    6. Register the java plugins:
    a. sudo update-alternatives –install /usr/bin/java java /usr/lib/jvm/java64/bin/java 1701
    b. sudo update-alternatives –install /usr/bin/java java /usr/lib/jvm/java32/bin/java 1501
    7. Create the symbolic link to plugins using 64bit version
    a. sudo ln -s /usr/lib/jvm/java64/lib/amd64/libnpjp2.so ~/.mozilla/plugins
    8. Set update-alternatives to link from /usr/sbin/ for Network Connect compatibility:
    a. sudo ln -s /usr/bin/update-alternatives /usr/sbin/
    9. Allow multi-arch libraries to get both necessary 32-bit libraries for Network Connect
    a. sudo dpkg –add-architecture i386
    b. sudo apt-get update
    10. Retrieve ia32-libs manually:
    a. sudo apt-get install libstdc++6:i386 lib32z1 lib32ncurses5 lib32bz2-1.0 libxext6:i386 libxrender1:i386 libxtst6:i386 libxi6:i386
    11. Verify 64 bit java environment is selected
    a. sudo update-alternatives –config java
    12. Restart Firefox and verify java at https://www.java.com/verify/
    13. Try to login to your SSL VPN page

    For every new or other existing user account on a Linux machine the following steps must be taken assuming the initial user account went through the prior 13 steps.

    1. Using a terminal session, make the Mozilla plug-in directory:
    a. sudo mkdir ~/.mozilla/plugins
    2. Register the java plugins:
    a. sudo update-alternatives –install /usr/bin/java java /usr/lib/jvm/java64/bin/java 1701
    b. sudo update-alternatives –install /usr/bin/java java /usr/lib/jvm/java32/bin/java 1501
    3. Create the symbolic link to plugins using 64bit version
    a. sudo ln -s /usr/lib/jvm/java64/lib/amd64/libnpjp2.so ~/.mozilla/plugins
    4. Allow multi-arch libraries to get both necessary 32-bit libraries for Network Connect
    a. sudo dpkg –add-architecture i386
    b. sudo apt-get update
    5. Retrieve ia32-libs manually:
    a. sudo apt-get install libstdc++6:i386 lib32z1 lib32ncurses5 lib32bz2-1.0 libxext6:i386 libxrender1:i386 libxtst6:i386 libxi6:i386
    6. Restart Firefox and verify java at https://www.java.com/verify/
    7. Try to login to your SSL VPN page.

    • Praise the lord! this worked like a charm for me! No more hoop jumping through Windows VMs and DSID stuff!

      Although — I used the method in this tutorial for months and it worked like a charm (saved my bacon in fact).

      Thanks to both of you!

  28. Some updates:
    – Somehow Scotts solution stopped working with Linux Kernel 3.19 on Ubuntu 14.10 x86_64
    – I can confirm: openconnect can be used to connect to a juniper vpn server. I tested trunc v7.04 on a Raspberry Pi, 3.18.7+ armv6l. You still need to catch the DSID cookie separately – at least I was not able to pass in user, password and token (into openconnect) in one go – anyway, once you caught the DSID you pass it to openconnect the same way you passed it to ncui … >> openconnect –juniper JUNIPER.SSL.SERVER.URL –user=philipp –sslkey=.your.server.crt –cookie=”DSID=985b7989dc3ba6ad62b538b154f210d5″

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>