Slow SSH login

tl;dr – my SSH client was attempting an IPV6 connection; my internet connection does not support IPV6

So. For a couple of weeks now, on and off, I’ve been trying to track down the source of my personal server being slow to log in via SSH.  IT was slow… say… 98% of the time, and 2% of the time it was fast.

I thought maybe it was compromised somehow (and I did find some xmlrpc pingback reflection attacks being done using a site of mine… which I fixed) but it didn’t appear to be so.

Then I thought maybe it was some sort of network exhaustion. But my bandwidth, and my tcp connections as reported by netstat all looked very low.

I had some swap used, so I thought maybe there was something important in swap slowing the system down.

I checked the usual suspects (dns resolvers, etc) and nothing. I checked my 2 factor authentication setup. Again nothing. I checked my sshrc script. Nada.

Turning to google and the various .*exchange(like)? site answers I tried setting usedns to no, and GSSAPIAuthentication to no. I cleared out some hosts.deny|allow entries, I even disabled some dynamic things in PAM for SSH, and finally turned PAM authentication off completely.  disabled and configured the server not to use avahi

Nothing worked. Everything looked good… sshd loglevel was set to verbose and not giving me any signs… using ssh -v to connect didn’t show me anything out of the ordinary

Well that’s not true. It showed the problem but it wasn’t an “error”, so to speak, and so I didn’t immediately notice it.

It turns out that, since my server has an IPV6 address my ssh client was attempting to connect to it via IPV6 first.  This is problematic because my internet connection has no such support.

Setting “AddressFamily inet” for “Host *” in .ssh/config fixed things right up.

I want to say this started happening right around the time I upgraded to OSX Yosemite (GM candidate), but I couldn’t swear to that.

Debian, ProFTPD, FTPS, TLS, SSL, and SSL23_GET_SERVER_HELLO:unknown protocol

Recently I needed to test against an FTPS server. No big deal, I thought to myself, I’ll just set one up real quick. Boy did I end up having a hard time with that. Not because the task was actually hard but because there’s a bit of a general haziness about the whole idea of what FTPS is. More on that later.

The first thing I did was setup my Debian ProFTPD server via the included /etc/proftpd/tls.conf. Restarted ProFTPD, and then tried curl -v -v -k ‘ftps://localhost’ which immediately resulted in the following error

* About to connect() to localhost port 990 (#0)
*   Trying 127.0.0.1... Connection refused
* couldn't connect to host
* Closing connection #0
curl: (7) couldn't connect to host

Oh, right, It’s listening on port 21 not port 990… curl -v -v -k ftps://localhost:21/ which gave me this error

* About to connect() to localhost port 21 (#0)
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 21 (#0)
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol
* Closing connection #0
curl: (35) error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol

Believe it, or not, I got stuck here for more than an entire day. Which is kind of embarrassing. I googled the hell out of this issue, and got lots of advice which centered about generating appropriate certs, and using “openssl s_client -connect 127.0.0.1:21” to test (which resulted in, essentially, the same error: “14996:error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol:s23_clnt.c:607:” )

With the help of a friend from work we found what I had been overlooking. You see FTPS can mean one of two very different things.

FTPS can mean FTP with explicit SSL. This is where you connect to FTP, then give a command to encrypt the session after the initial plaintext connection has been established.

FTPS can also mean FTP with implicit SSL. This is where you connect to the ftp server and the connection is encrypted before any commands are sent (this is like having HTTP on port 80 and HTTPS on port 443, except using 21 and 990 for FTP.)

The two types of FTPS are not compatible with one another. Apparently FTPS/Implicit is no longer a part of the standard, but still “around” and “supported” by “things”. And curl thinks you mean this when you give it a url of ftps://something. FTPS/Implicit is also the kind of stream that “openssl s_client -connect 127.0.0.1:21” would test. FTPS/Implicit is not the configuration setup by /etc/proftpd/tls.conf. Which is why my testing failed, frustratingly, for so long.

Since ProFTPD uses FTPS/Explicit by default… how do you test? With very similar commands to the ones I used previously (lending to the confusion…)

openssl s_client -connect 127.0.0.1:21 -starttls ftp
curl -v -v -k --ftp-ssl ftp://localhost:21/

Ok. Now I’m able to setup and test an FTP/E server. What if I also need to setup and test an FTP/I server too? Thats pretty simple. in ProFTPD 1.3.3rc2, the mod_tls module was enhanced to support implicit FTPS via the UseImplicitSSL TLSOption. So by adding “TLSOption UseImplicitSSL” on an appropriately new version of ProFTPD and mod_tls you can have a server that works with “curl -v -v -k ftps://localhost:21/” and “openssl s_client -connect 127.0.0.1:21”

I hope that this saves someone else the headaches that going through all of this gave me. Had I read through the ProFTPD TLS howto carefully, instead of just searching for what I thought I needed, I would have solved this all much more quickly.

Adding a second authentication factor to WordPress

UPDATE: I’ve added the plugin to the WordPress.org repository. If it gathers interest/attention then I may develop it further and add more stuff like SMS gateway support, configuration, etc… See: http://wordpress.org/extend/plugins/second-factor/

I really don’t know why, but the idea of adding a second authentication factor to WordPress blogs took hold of my brain tonight and needed an outlet. So I made this little proof of concept plugin: Second Factor. What it does is pretty simple:

  1. When you log in it goes through a series of cryptographic routines and generates some info which is stored in the database as a user option.
  2. A key is generated for you, and an email is sent to your listed email address.
  3. When you attempt to access a page while logged in it blocks you, asking for the key that was emailed to you
  4. Finally after entering this second authentication token you are allowed access to the site

I could see this being extended to Instant Messaging, SMS, IRC, or even integrated with a text-to-phone service to make an actual phone call which reads off the numbers to you.

What I don’t know is if anyone actually wants this… If this is even worthwhile. For me it was mainly a thought experiment. Would you want to have this kind of added security on your WP Installation?

Using PHP and OpenSSH with username/password auth

It turns out that this is actually a tricky problem. It’s super easy to use the OpenSSH command line stuff via PHP when you have key based authentication set up, but it’s not at all easy to use when you want to go the user/pass route. This is for a couple of reasons:

First you cannot specify the password on the command line. Second you cannot use the php process controls directly to give the password (well this isn’t 100% true, if you want to recompile your PHP binary with pty support then you probably could bypass everything I’m about to say and just use proc_open straight). And there’s a third reason that I’ll get to in a bit.

OpenSSH supports getting a password from an executable program via the SSH_ASKPASS environment variable — with two notable gotchas. First this only works if you also specify a DISPLAY environment variable, and second it does NOT work if the controlling process has a tty or pty.

The code below works… but if you just paste it into a script file and run it directly with php ./myscript.php it fails. Why?

function ssh_user_pass_port_forward( $hostname, $username, $password, $localport, $remotehost, $remoteport ) {
	$descriptorspec = array(
	        0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
	        1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
	        2 => array("pipe", "w")   // stderr is a file to write to
	);
	$script = tempnam( '/tmp/', 'askpass-');
	file_put_contents( 
		$script, 
		"#!/bin/bash
echo -n ".escapeshellarg( $password ) 
	);
	chmod( $script, 0755 );
	$env = array( 
		'DISPLAY' => '0', 
		'SSH_ASKPASS' => $script 
	);
	$forward = sprintf(
		"%d:%s:%d",
		$localport,
		$remotehost,
		$remoteport
	);
	$command = sprintf(
		"/usr/bin/ssh -n -o StrictHostKeyChecking=no -l %s -L %s -N %s",
		escapeshellarg( $username ),
		escapeshellarg( $forward ),
		escapeshellarg( $hostname )
	);
	return proc_open( $command, $descriptorspec, $pipes, getcwd(), $env);
}

The answer is that you are running it, and you’re running it from a shell which has a tty or pty attached, and the script inherits those and OpenSSH sees this and then ignores the SSH_ASKPASS variable completely. The trick to testing/using this code is to execute it without running it from a terminal. If you execute the command below (roughly) it looks like it hangs. but if you open another terminal you should be able to use the port forward just created.

ssh myserver.com “php /path/to/myscript.php”

This is because since you’re sshing for the sole purpose of running that command and not using a shell the system doesn’t allocate you a pty like it would normally. I’m guessing that executing it via an http request would do something similar.

Since I previously posted some hard-won advice for working with ssh2_* in php I thought I would share this equally tricky bit that I’d also figured out in the process.

Remember that there is ALWAYS more than one way to skin a problem, and every problem can be skinned with enough effort.

Again, this is itch-scratch-ware, YMMV, this is meant as a starting point on a journey to a solution and not a drop-in-works-everywhere bit of code. It’s just the hard stuff. The useful stuff is still up to you 😉

PHP SSH2 code

I’ve had a need to use the PHP SSH2 PECL recently (working on making a product, at work, more efficient) And thought I would share some of the preliminary code. You can find it here: vpssh.phps

The most interesting thing is not vpssh_core or it’s exec (though it’s good code) the really interesting thing is the vpssh_tunnel class and the accompanying examples at the top of the file. This really shows some advanced usage of ssh2_tunnel that you can’t really find anywhere else.

It’s just the beginnings of some useful code, but it’s probably a huge jumping off point for anyone seriously looking into the ssh2 pecl functionality. Oh, it also works with both password and key based authentication.

This code is less than 12 hours old, and it works for me so far, YMMV. Feedback welcome … or not… Whatever. Hope it helps someone out. And I hope it helps me out later when I need this kind of thing again.

Postfix, DKIMproxy, Spamc

If you’re running any moderately busy mail server you’re probably using spamassassins spamc/spamd to check for spam because its tons more efficient than piping the mail through the spamassassin cli. Assuming that you do, and that you plan on adding DKIM proxy to the mix to verify  and sign emails you need to put things in the right order, to save you some headache here’s what I did:

  1. smtp|smtps => -o smtpd_proxy_filter=127.0.0.1:10035 # outgoing dkim verify port
  2. 127.0.0.1:10036 => -o content_filter=spamassassin
  3. spamassassin =>  pipe user=nobody argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient} # this delivers to the “pickup” service
  4. pickup => -o content_filter=dksign:127.0.0.1:10037 # outgoing dkim signing port
  5. 127.0.0.1:10038 => -o content_filter= # the buck stops here

If you arent careful with these (which I wasnt) you’ll end up causing an infinite loop between your filters (which I did).  Thus concludes our public service announcement.