Hello folks!  I'm Bcc:ing security-dicuss since this is an IPsec matter, but
really it's about protocol processing which falls squarely in the networking
half of the shop.

One of my little side-projects is eliminating the "nattymod" STREAMS module
and replacing it on the user-land side with a UDP_NAT_T_ENDPOINT socket
option.

What nattymod does and its replacement will do are:

        * If first four bytes after the UDP header are 0, remove those four
          bytes and pass up like an ordinary UDP packet.  (This is for IKE or
          some other IPsec Key Management daemon.)

        * Otherwise, it's an ESP-in-UDP packet, and we strip out the UDP
          header, and feed the packet into IPsec's ESP (where that NAT-T
          flags will make ESP do a few additional post-decryption things).

        * On the transmit side, insert the 0-SPI on app-sent UDP packets.

        * Occasionally use qtimeout() or something else to send one-byte
          keepalives to keep NAT boxes from doing dumb mapping things.

        * Discard one-byte keepalives to prevent packet pollution.

Having this functionality inside IP keeps a lot of STREAMS juggling out of
the way since UDP is now part of the greater TCP/IP co-prosperity sphere.

My initial thoughts were to just swap in a new conn_recv when that option was
set.  Problem is, UDP doesn't use conn_recv like TCP does!!!  It uses this
macro:

#define CONN_UDP_RECV(connp, mp) {                                      \
        if (IPCL_IS_UDP(connp))                                         \
                udp_conn_recv(connp, mp);                               \
        else                                                            \
                putnext((connp)->conn_rq, mp);                          \
}

I was going to rewrite the macro as follows:

#define CONN_UDP_RECV(connp, mp) {                                      \
        if (IPCL_IS_UDP(connp))                                         \
                connp->conn_recv(connp, mp, NULL);                      \
        else                                                            \
                putnext((connp)->conn_rq, mp);                          \
}

where udp_conn_recv() becomes a 3-argument conn_recv function.

I'd prefer not to use the heavier-weight approach of having stock udp_input()
check for the socket option on every packet regardless.  I do realize,
though, that I may need to generate/write two functions that look awfully
similar, or have callouts or macros for lots of udp_input()'s functionality.

One concern is that if this is an ESP-in-UDP packet, ESP needs more
information than UDP (thanks to potentially async. crypto).  Maybe we can
pass a pointer to all of that in a 3rd argument to conn_recv(), but
generating all of that for every UDP packet makes little sense?

Maybe we detect UDP_NAT_T_ENDPOINT in IP, and introduce that one check there.
That might also allow us to do ESP-in-TCP ala. the cisco VPN.

I welcome your thoughts on this.  I'm dinking with it now, so nothing I say
here is in stone.  I was hoping to crank a crude prototype out, but the whole
ESP-requires-more problem made me think I should ask here.

Thanks!
Dan

Reply via email to