The Sapience Society The advice of a self-proclaimed technological ninjician

30Jan/0918

Connect to Windows Samba Shares via SSH Tunneling from Mac OS X

Chances are if you are seeing this, you've tried quite a bit but it hasn't worked. Look no further. If you are seeing this and haven't been researching it, then this should still be enough info to get a good start.

First, here's the point: Using windows file sharing (Samba/SMB) is a good way to access your files across your home network, but don't even think about trying it over the internet. In order to access SMB shares across the internet you're going to need to get creative. A method which works reasonably well is using a zero-configuration VPN program such as Hamachi, Remobo, Wippen, etc. to create a virtual lan connecion, thus fooling your computer into connecting like you were on the same lan. That works, but in my experience it isn't very reliable, it has limitations, it has overhead, and it means you have to have that ZCVPN client on both ends. So here's my solution, skip the program, jump straight to the solution. If you use an SSH tunnel to connect to your computer, you can access your SMB shares, you can use VNC to view your screen, or do just about anything that uses a port on your host computer. The best part about it is, once you have it up and running, it's really simple to use!

Note: This post will assume that your "server" machine is running windows and your "client" machine is running Mac OS X Leopard.

Here's how to do it:

1. Enable file sharing on your host computer (I'm going to assume this is running Windows). This will allow your files to be shared across your local network. If you don't know how to do that, there's a very good guide Here.

2. (Optional) Disable simple file sharing and edit the permissions on your shares so that the shares are password protected. You only need to do this if you don't want just anyone on your local network to be able to access your files. (Google it)

3. Install an SSH server on your host computer, I'd recommend freeSSHd. This will allow your to create a secure connection between your computers. I'd suggest freeSSHd because it's free and much easier to use than many of the alternatives (OpenSSH/Cygwin).

4. On the SSH tab in the freeSSHd settings, change the port to whatever port you want, I'll be using 12345 in my examples. I'd recommend something in between 10000 and 50000 so that a network scanner is less likely to pick up the port.

5. On the Users tab in freeSSHd, add a user with the username and password of your choice, set your password as "Password stored as SH1 hash".

6. On the Tunneling tab in freeSSHd, enable local and remote port forwarding.

7. Test your SSH server to make sure you can connect to it using a computer on the same network as the SSH server. You will need the local IP of the SSH server for this step you can find it using This guide.

To test it from your mac machine:

  1. Open the Terminal (Applications/Utilities/Terminal)
  2. Use the command ssh -p port username@hostip (Example: ssh -p 12345 [email protected])

8. Enable port-forwarding on your router to your SSH server at the port you used - Follow one of the guides for your router Here but use the port for SSH (12345)

9. (Optional) Set up an automatic DNS server for your host computer, you can set that up Here for free. I'd really suggest you do this, its very useful! Once you have that set up, install the No-IP Dynamic Update Client so that your DNS always matches your dynamic IP.

10. Test your SSH connection via the port forward. This is almost exactly the same as before, except instead of using the IP you got from ipconfig, use your global IP (or the DNS you set up in step 9). You can find your global IP Here. Example: ssh -p 12345 [email protected]

Now that we have all that set up, we're almost done. What we're going to do is connect via SSH and forward the SMB ports from our host computer to our client. This will allow you to access your shares remotely. It works because your ssh/smb server will think that it's directly connected with your client computer, when in fact the connection is all handled through SSH. The tricky part is, OS X Leopard will not allow you to do this. If you forward the SMB ports from the server to client computer, then the client will think that it's connecting to itself, and so Leopard will deny the connect. In order to defeat this we're going to have to work some magic.

11. Set up an alias for your loopback connection (localhost/127.0.0.1) on your Mac. This will fool your computer into thinking it's connecting to an external IP. This command needs admin privileges, so you have to use sudo. The command is:

sudo ifconfig lo0 127.0.0.2 alias up

This will create a temporary alias for your loopback connection which will stay active until the computer is restarted.

12. Edit the all users configuration file for your SSH settings so that you can connect quickly without setting it up each time.

  1. Open the Terminal and run sudo pico /etc/ssh_config
  2. Enter the following text above the line that says " #Host *", change the user and port to the ones you have used in your SSH configuration.

Host AliasForHost
HostName hostip
Port 12345
User YourUserName
ServerAliveInterval 200
ServerAliveCountMax 3
LocalForward 127.0.0.2:139 127.0.0.1:139
LocalForward 127.0.0.2:445 127.0.0.1:445

Keep in mind that you can add any number of ports to this list. For example, if you want to connect to VNC, add 5900 to that list. Then to use VNC, connect to 127.0.0.2:5900.

Hit control + x, Y, and enter to save the file. Since we're saving it as a dotfile (there's a dot at the beginning) you won't be able to see it. If you need to edit it again, you can do it through pico the same way.

13. Initiate the SSH connection with your host computer using the host alias we set up before.

sudo ssh AliasForHost

14. Connect to the Samba share. Open a Finder window and hit command+ k to open a Connect to Server windows. For the server address, use:

smb://127.0.0.2

Now click Connect, and if everything went well you should be prompted with a window to enter your Login credentials for the server machine!

Wow, that was complicated, but at this point it doesn't need to be. Here's a little AppleScript I came up with to automate the connection. (Don't worry about running the ifconfig over and over, it won't hurt anything)

set Command to "sudo ifconfig lo0 127.0.0.2 alias up; sudo ssh AliasForHost"

tell application "Terminal"
if (count of windows) is 0 then
do script Command
else
do script Command in window 1
end if
activate
end tell

You can save that script as an application using the AppleScript Script Editor and run it to automatically run those commands.

I know for most people that post was probably really confusing but I tried! If you need help please comment or something. I'll get back to you.

Edit: Take a look at Fredrik's script in the first comment for  an even more automated solution for connecting and mounting.

Edit2: I found a much more efficient way to actually initiate the connection using a host alias, take a look at the part about the ssh_config file

Comments (18) Trackbacks (1)
  1. Yes! Thank you finally a decent solution to mount samba over a public net..

    I’ve created a shell script like this:

    cat ~/bin/mount_ftp
    sudo ifconfig lo0 127.0.0.2 alias up
    sudo ssh user@host -F ~user/.sshForward -N &
    mkdir -p /Volumes/ftp
    mount_smbfs //:@127.0.0.2/ftp /Volumes/ftp

    Seems to be working fine as well..

  2. Very interesting site, Hope it will always be alive!

  3. Can anyone tell me how to do this strictly from cmd line. I don’t want to edit any of my config files. I want to manually setup the tunnels every time. I want to do it this way so that I can make sure that I understand EXACTLY what I am doing. I am pretty experienced with SSH, but the whole not being able to push my SMB connection through the tunnel b/c of the OSX restriction on connecting to localhost is stopping me. Thanks.

  4. I love it! That is way cool man! The steps weren’t that complicated too, which is great.

  5. @mike
    It’s quite possible to do but the command gets to be quite long. You could probably figure it out just based on the man pages for ssh on mac, but I’d start with something like:

    sudo ifconfig lo0 127.0.0.2 alias up
    sudo ssh -L 127.0.0.2:139:127.0.0.1:139 -L 127.0.0.2:445:127.0.0.1:445 -p RemoteSSHPort user@hostname

    I’m not sure if using -L twice like that will work, but if it does, that’s how you’d do it.

  6. @lococobra
    double -L works fine – but it qoutes wor password also twice (if you don’t use key-pairs).

  7. da best. Keep it going! Thank you

  8. Hey, this guide is just what I’m looking for. …Except, I can’t get it to work :/ I have the server ssh set up (using Cygwin/openSSH), and I’m connecting with the client ssh_config file configured as specified (I believe the port forwarding is enabled, as ssh won’t let me connect to that host alias without sudo, due to “privileged port” issues (i’m using 22)).
    But when I try to command-K in finder and connect to smb://127.0.0.2/ I end up seeing my own Public Folder. Not so exciting…

    Is there perhaps some OpenSSH configuration I need to configurate, to enable port tunneling? I note there was a step concerning that with your freeSShd example.

    Cheers, and thanks for the guide.

  9. Hmm, got it to work – by commenting out the line in the ssh_config that referred to port 139. All our SMB is over port 445 – not sure why that line wasn’t being acted upon?

    Thanks heaps for taking the time to document this – the localhost alias was non-obvious :)

  10. Hey,

    I used this guide a few months ago to get my macs and pcs hapilly living together. Thanks sooo much for it!!!! Everything has worked fine so far for me, after following the guide step by step. However, I was just a tad bit irritated that I had to provide a bunch of user inputs to os x when mounting a drive.

    I wanted to automate all this stuff; essentially, I wanted to mount the drive by simply executing an AppleScript.

    To get this to work, you’ll have to do a few things. [1] You’ll need to be using public/private key authentication so that you don’t have to type in your password to the terminal every time the ssh tunnel is built. [2] You’ll have to generate a key-pair both for your user account that you’re using to mount the drive and the root user. This is required for the root user b/c you’re having to use root to set up the virtual network drive. Log into each, generate the key pair, load the pair up in your windows box ssh server, and you should be good to go.

    After that’s set up, you should be able to run the script outlined in the guide (the stuff above, not mine) to build the virtual network drive and set up the ssh tunnel.

    Just an extra line can automate the mounting process:
    mount volume “smb://127.0.0.2/drives” (‘drives’ is a shared folder on my windows box).

    However, this wasn’t quite good enough for me. I use chronoSync to sync folders (I actually drive all my windows backup copies with my mac using chronoSync; I don’t trust Windows at all :) ), and for those folders to sync, the ‘drives’ volume has to be mounted. Now, before running the sync, you could just run the entire AppleScript, ensuring that the drive is mounted. However, if the drive was already mounted, or the ssh bridge has already been set up, or the virtual network card has already been created, then you’re essentially calling this stuff all over again, potentially creating multiple ssh tunnels, conflicting virtual network cards, etc…

    So…. I took care of all the case statements and wrote this AppleScript that automates the routine of ‘mounting a PC-hosted Samba-shared drive on an OS X machine via an ssh tunnel’. I’m posting the code at the end of my message.

    I went for readability over cleverness in coding. This script should almost be english readable (as an AppleScript should be).

    You’ll have to configure a few things in the code for your specific system. The big stuff:
    [1]: Your ‘ssh_config’ file will have a ‘host’ with a particular name. Mine was ‘cstanley’.
    [2]: Your ip address you used for the virtual network card might not be 127.0.0.2; if it isn’t, change the code
    [3]: This string: cpe-71-64-144-19.ssh : is the ssh tunnel that’s set up. The leading numbers are specific to a particular computer (I think), so they should never change since you’re always connecting to the same machine. Just find out what your connection looks like by using ‘netstat -p tcp’, and alter accordingly.

    Other than that, just google around if you don’t understand any of the commands, and think a bit about how you can mesh it with your setup. Shouldn’t be too much of a pain. I have this script set to run before every sync in ChronoSync. Using it, regardless of the current state of the connection between my mac and pc, the correct pieces will be run to get the connection back in shape and mount the drive.

    Let me know if any of this was useful to anyone…

    Happy Coding!!!!
    -Clayton

    /////////////////////////////////////////////////////////////////////////

    on checkProcess(processName)
    tell application “System Events”
    set isRunning to ((application processes whose (name is equal to processName)) count)
    end tell
    if isRunning is greater than 0 then
    return true
    else
    return false
    end if
    end checkProcess

    set CommandDummyCard to “sudo ifconfig lo0 127.0.0.2 alias up”
    set CommandMakeTunnel to “sudo ssh cstanley”
    set killTerminals to 0
    set commenting to false

    set ping_result to (do shell script “ping -c 1 -t 2 127.0.0.2; echo -n”)
    if ping_result does not contain “100% packet loss” then
    if commenting then
    display dialog “virtual network card already created”
    end if
    else
    if commenting then
    display dialog “virtual network card not yet created”
    end if
    if not checkProcess(“Terminal”) then
    tell application “Terminal”
    run
    close front window
    end tell
    delay 2
    end if
    tell application “Terminal”
    do script CommandDummyCard
    end tell
    set killTerminals to killTerminals + 1
    delay 2
    end if

    set netstat_result to (do shell script “netstat -p tcp | cut -c 45-66″)
    if netstat_result contains “cpe-71-64-144-19.ssh” then
    if commenting then
    display dialog “ssh tunnel already built”
    end if
    else
    if commenting then
    display dialog “ssh tunnel not yet built”
    end if
    if not checkProcess(“Terminal”) then
    tell application “Terminal”
    run
    close front window
    end tell
    delay 2
    end if
    tell application “Terminal”
    do script CommandMakeTunnel
    activate
    end tell
    set killTerminals to killTerminals + 1
    delay 2
    end if

    set netstat_result to (do shell script “netstat -p tcp | cut -c 22-44″)
    if netstat_result contains “127.0.0.2.microsoft-ds” then
    if commenting then
    display dialog “drive already mounted”
    end if
    else
    if commenting then
    display dialog “drive not yet mounted”
    end if
    mount volume “smb://127.0.0.2/drives”
    delay 2
    end if

    repeat while killTerminals > 0
    if commenting then
    display dialog “killTerminals currently” & killTerminals
    end if
    tell application “Terminal”
    close front window
    end tell
    set killTerminals to killTerminals – 1
    end repeat
    if commenting then
    display dialog “killTerminals currently ” & killTerminals
    end if

    /////////////////////////////////////////////////////////////////////////

  11. @clayton stanley

    Thanks for your input! You really took my idea and ran with it haha. I’m going to have to try that out on my end. Would you consider writing for this blog? If you have any other ideas like that I’m sure there are a lot of people who would like to hear about them!

  12. @lococobra

    How did my code work out for you? Thanks again for this initial post; I spent a year before setting this up, struggling with MacFuse and MacFusion, to try and get my Macs able to mount PC drives across the net.

    I wouldn’t mind writing in every now and then; although this was my first AppleScript, so I’m not sure how much more AppleScripting I’ll be doing…..

    I’ve been into VBA and Outlook lately; I’m trying to build a synchronizer between two outlook folders in/across .pst files… I’m just polishing the code now; not sure if that solution should really go here though…

    I’d be happy to keep developing this AppleScript though, if anyone has any suggestions… I think I might delve into MikeD’s suggestion; get away from configuring the ssh_config file and hard code everything into the AppleScript.

    I’ll post here if I do make any updates.

    -Clayton

  13. I get this error message:
    shell request failed on channel 2

    when i do this

    sudo ifconfig lo0 127.0.0.2 alias up
    sudo ssh Aliashost -i .ssh/rsakey (password protected)

    netstat -p tcp
    no 139 or 445 records

    Any one?

  14. @Marc

    Does ssh actually connect? (that can be confirmed by checking connected users on the remote computer) Are there any errors? If it does you shouldn’t be able to run other commands in that tab until you close the session.

  15. @2can

    This works great; if you’re using my script, just change the string variable ‘setCommandMakeTunnel’ to this long ssh command; then no more needing the ssh_config file

    And you don’t have to use the [-p remoteSSHPort] if your remote ssh port is the default ssh port (i.e., port 22)

  16. not sure if 2can’s comments are going to be put by mine, so I’ll repost the command:

    “sudo ssh -L 127.0.0.2:139:127.0.0.1:139 -L 127.0.0.2:445:127.0.0.1:445 user@hostname”

    change ‘user’ and ‘hostname’ to suit your needs

    -clayton

  17. These suggestions are awesome.

    Here’s a Terminal command for mounting an SMB share by tunneling through an SSH server (e.g. when the SSH server is the only access point through the firewall):

    “sudo ifconfig lo0 127.0.0.2 alias up ; sudo ssh -NL 127.0.0.2:139:SMB.ADDRESS:139 -NL 127.0.0.2:445:SMB.ADDRESS:445 [email protected]

    SMB.ADDRESS = the I.P. address or domain name of the SMB share.
    SSH.SERVER.ADDRESS = the I.P. address or domain name of the SSH server

    After executing this command you will be prompted twice:
    1. For the sudo (admin) password on your Mac, then
    2. For the SSH server password.

    Now use the standard “Connect to Server” dialogue from the menu bar with:
    smb://[email protected]
    Now you will be prompted for the SMB username and password.

  18. That’s exactly the same as what I suggested :P


Leave a comment

(required)