views:

230

answers:

4

I'd like to write a simple command line proxy in Python to sit between a Telnet/SSH connection and a local serial interface. The application should simply bridge I/O between the two, but filter out certain unallowed strings (matched by regular expressions). (This for a router/switch lab in which the user is given remote serial access to the boxes.)

Basically, a client established a Telnet or SSH connection to the daemon. The daemon passes the client's input out (for example) /dev/ttyS0, and passes input from ttyS0 back out to the client. However, I want to be able to blacklist certain strings coming from the client. For instance, the command 'delete foo' should not be allowed.

I'm not sure how best to approach this. Communication must be asynchronous; I can't simply wait for a carriage return to allow the buffer to be fed out the serial interface. Matching regular expressions against the stream seems tricky too, as all of the following must be intercepted:

delete foo(enter)
del foo(enter)
el foo(ctrl+a)d(enter)
dl(left)e(right) foo(enter)

...and so forth. The only solid delimiter is the CR/LF.

I'm hoping someone can point me in the right direction. I've been looking through Python modules but so far haven't come up with anything.

+5  A: 

Python is not my primary language, so I'll leave that part of the answer for others. I do alot of security work, though, and I would urge a "white list" approach, not a "black list" approach. In other words, pick a set of safe commands and forbid all others. This is much much easier than trying to think of all the malicious possibilities and guarding against all of them.

Devin Ceartas
Excellent point, and I should have noted this in the question, but unfortunately a user could device a virtually infinite number of command deviations. Imagine trying to whitelist all possible Bash commands when all you want to do is block variations of 'rm'.
There is an almost endless list of bash commands that could, not delete a file, but overwrite it. That could be just as damaging as delete. Sounds like a tough problem.
Craig McQueen
A: 

As all the examples you show finish with (enter), why is it that...:

Communication must be asynchronous; I can't simply wait for a carriage return to allow the buffer to be fed out the serial interface

if you can collect incoming data until the "enter", and apply the "edit" requests (such as the ctrl-a, left, right in your examples) to the data you're collecting, then you're left with the "completed command about to be sent" in memory where it can be matched and rejected or sent on.

If you must do it character by character, .read(1) on the (unbuffered) input will allow you to, but the vetting becomes potentially more problematic; again you can keep an in-memory image of the edited command that you've sent so far (as you apply the edit requests even while sending them), but what happens when the "enter" arrives and your vetting shows you that the command thus composed must NOT be allowed -- can you e.g. send a number of "delete"s to the device to wipe away said command? Or is there a single "toss the complete line" edit request that would serve?

If you must send every character as you receive it (not allowed to accumulate them until decision point) AND there is no way to delete/erase characters already sent, then the task appears to be impossible (though I don't understand the "can't wait for the enter" condition AT ALL, so maybe there's hope).

Alex Martelli
I mean that I can't buffer the whole thing up until CRLF; it needs to be pass-though for things like tab-completion to function properly.
OK, but, can you "cancel" or "erase" as I said just before passing on the connect? That's the crux of the issue. Also, if the serial device is so sophisticated that you can't emulate its commands, e.g. tab completion, it may be possible to construct the current state of the line not by emulation but by grabbing the device's response bytes as you're passing them back to your client -- hard to say more without further details.
Alex Martelli
A: 

After thinking about this for a while, it doesn't seem like there's any practical, reliable method to filter on client input. I'm going to attempt this from another angle: if I can identify persistent patterns in warning messages coming from the serial devices (e.g. confirmation prompts) I may be able to abort reliably. Thanks anyway for the input!

A: 

Fabric is doing a similar thing.

For SSH api you should check paramiko.

iElectric