Hi Stuart,

On May 1, 2013, at 1:11 AM, Stuart Henderson <st...@openbsd.org> wrote:

> On 2013/05/01 00:16, Franco Fichtner wrote:
>> 
>> Yes, I am proposing a lightweight approach: hard-wired regex-like
>> code, no allocations, no reassembly or state machines.  I've seen
>> far worse things being put into Kernels and I assure you that I do
>> refrain from putting in anything that could cause segmentation
>> faults, sleeps, or other non-suitable behaviour.
> 
> Would it be fair to describe it as a bit more complex than osfp,
> but not hugely so?

Not sure if that's a fitting comparison; and I know too little OSPF
to answer.  Let me try another route.  The logic consists of an array
of application detection functions, which can be invoked via their
respective IP types.  There's 32 bits of external state for the
table and a single hook into the application detection.  And the
detection for TLS/SSL3.0 follows.  I have really tried to condense
it down to the bare minimum.

LI_DESCRIBE_APP(tls)
{
        struct tls {
                uint8_t record_type;
                uint16_t version;
                uint16_t data_length;
        } __packed *ptr = (void *)packet->app.raw;
        uint16_t decoded;

        if (packet->app_len < sizeof(struct tls)) {
                return (0);
        }

        decoded = be16dec(&ptr->data_length);

        if (!decoded || decoded > 0x4000) {
                /* no empty records possible, also <= 2^14 */
                return (0);
        }

        switch (ptr->record_type) {
        case 20:        /* change_cipher_spec */
        case 21:        /* alert */
        case 22:        /* handshake */
        case 23:        /* application_data */
                break;
        default:
                return (0);
        }

        switch (be16dec(&ptr->version)) {
        case 0x0300:    /* SSL 3.0 */
        case 0x0301:    /* TLS 1.0 */
        case 0x0302:    /* TLS 1.1 */
        case 0x0303:    /* TLS 1.2 */
                break;
        default:
                return (0);
        }

        return (1);
}

>> Would a protocol like BGP have a bright future in relayd(8)?
>> I don't know enough, maybe Reyk can clear this up?
>> 
>> L7 filtering is cute, but ipfw-classifyd isn't maintained, DPI in
>> Linux netfilter is not hitting it off, and there really is no
>> BSD DPI.  Franky, I don't care which way to go, but I believe
>> that pf(4) is a suitable candidate.  I especially like the one-
>> rule-to-rule-them-all approach.  Adding a keyword "app" to
>> pf.conf(5) seems like the simplest solution -- much like "proto"
>> does deal with IP types.
>> 
>> And talking about complexity: 1000 LOC for 25 protocols.  I'm afraid
>> it can't be simplified any more than this.
> 
> What sort of protocols do you think could be reasonably handled by
> this approach, and what would be too complicated?

Good question!  Text protocols are easy, RFCs and open implementations
are generally easy.  Anything too commercial/proprietary, especially
in binary, is more guessing than anything else and may not be worth
the effort.  I don't see "world of warcraft" happening as a supported
application.  This is what I have done so far (by no means free of
errors, though):

-- BitTorrent
-- Gnutella
-- Network Basic Input Output System
-- Telecommunication Network
-- Hypertext Transfer Protocol
-- Post Office Protocol (Version 3)
-- Internet Message Access Protocol
-- Simple Mail Transfer Protocol
-- Session Traversal Utilities for NAT
-- Dynamic Host Configuration Protocol
-- Point-to-Point Tunneling Protocol
-- Lightweight Directory Access Protocol
-- Simple Network Management Protocol
-- Secure Shell
-- File Transfer Protocol
-- Session Initiation Protocol
-- Domain Name System
-- Real-time Transport Control Protocol
-- Real-time Transport Protocol
-- Routing Information Protocol
-- Boarder Gateway Protocol
-- Internet Key Exchange
-- Datagram Transport Layer Security
-- Transport Layer Security
-- Concurrent Versions System

> There is definitely something appealing about being able to say, for
> example, 'block proto tcp on port 443; pass proto tcp on port 443 app tls',
> or 'block app ssh; pass proto tcp from <somehosts> to port 22 app ssh'
> without a bunch more complexity involved in passing across to a separate
> proxy (which would then need to implement its own completely separate
> filtering and would, I think, not really be able to integrate with
> things like PF tags and queue assignment)...

Yes, that would be one scenario.  I like to think of lightweight packet
inspection as application "tagging".  That's the first stage.  Second
stage is a real parser/proxy/endpoint.  It's not a security functionality
per se, but it can help to break down the workload.  It doesn't care
aboute IP versions, ports (mostly ;) ), different flavours ("netbios"
could be session, datagram, and name service as one for example), and so
forth.

> Basically what I'm wondering if it's possible to go far enough to be
> useful whilst keeping the complexity down to a level which is sane
> and simple enough that it can be carefully audited.

That is my concern as well and I have kept that in mind while working
on the code.  The current state of the art in DPI is somewhat messy,
so that's the reason for me to improve on it.


Franco

Reply via email to