Subject: RE: [Capwap] NAT-T

From: "Pat Calhoun (pacalhou)" <[email-masked]>
Date: Thu, 23 Mar 2006 14:37:58 -0800

I don't agree with the use of a single UDP port, as it would require the
state of DTLS to be the same for both data and control - certainly not
something that we've *ever* agreed to. In fact, the concept of DTLS for
data showed up in the latest document without discussion among the
editors and the WG. Must discussion needs to occur on this topic before
we can even assume it is a given.

My understanding is that the MUX is used to bind the control and data
plane, which could be useful if we have two UDP ports. However, you've
completely lost me as to why it would ever be required if we were to
make use of a single UDP port. Looking at HTTP, it certainly is
NAT'able, and there is nothing specific in that protocol that needs to
be done in order to support NAT.

Pat Calhoun
CTO, Wireless Networking Business Unit
Cisco Systems

> -----Original Message-----
> From: Scott G. Kelly [mailto:[email-masked]] 
> Sent: Wednesday, March 22, 2006 12:03 PM
> To: Pat Calhoun (pacalhou); capwap
> Subject: RE: [Capwap] NAT-T
> 
> Yes, I'm suggesting use of one port with a mux header rather 
> than 2 ports: it's much simpler operationally.
> 
> -----Original Message-----
> >From: "Pat Calhoun (pacalhou)" <[email-masked]>
> >Sent: Mar 22, 2006 11:27 AM
> >To: "Scott G. Kelly" <[email-masked]>, capwap 
> ><[email-masked]>
> >Subject: RE: [Capwap] NAT-T
> >
> >Scott,
> >
> >I'm not sure I follow.
> >
> >Are you stating that the MUX is a replacement for the dual UDP port 
> >solution? The latter allows existing NATs to handle the 
> packet, while 
> >the MUX is useful at the application layer. That said, I'm not sure 
> >that I understand why we cannot rely on the BSSID in the 
> 802.11 frame 
> >to identify the WTP.
> >
> >Pat Calhoun
> >CTO, Wireless Networking Business Unit
> >Cisco Systems
> >
> > 
> >
> >> -----Original Message-----
> >> From: Scott G. Kelly [mailto:[email-masked]]
> >> Sent: Wednesday, March 22, 2006 8:53 AM
> >> To: capwap
> >> Subject: [Capwap] NAT-T
> >> 
> >> Hi All,
> >> 
> >> A group of us met yesterday to discuss dtls integration, and one 
> >> related design point pertains to nat traversal. In 
> particular, how we 
> >> decide to handle directly impacts the design for dtls 
> integration, so 
> >> we want to get this resolved ASAP.
> >> 
> >> In the original lwapp-dtls draft, we discussed two options for 
> >> differentiation: use a mux header, or use separate UDP 
> ports, one for 
> >> data and one for control. Initial agreement seems to be on the 
> >> two-port approach, but this has nat-t implications.
> >> 
> >> Assume we're using two ports; in that case, the problem we have to 
> >> solve is many ways similar to the one solved by the ipsec 
> group (I'll 
> >> use NAT rather than NAPT, as it's simpler to type :-)):
> >> 
> >> - the WTP sends a DISCOVER to the AC; note that if this is 
> broadcast, 
> >> no reply would be possible using a standard NAT implementation, as 
> >> the NAT binding would be to the tuple (WTP-IP, BCAST-IP, UDP, 
> >> WTP-PORT, AC-PORT). Since the response would not be from BCAST-IP, 
> >> standard NAT implementations would drop it. This implies directed 
> >> DISCOVER messages
> >> 
> >> - *if* the AC responds within the NAT binding timeout 
> period (while 
> >> the mapping record still exists on the middlebox), the WTP will 
> >> receive the response; otherwise, it will be silently dropped
> >> 
> >> - assuming the WTP receives the response and wants to 
> associate with 
> >> the AC, it initiates the JOIN process (yes, the JOIN must 
> be brought 
> >> back, more on that later). One or both sides must also start a 
> >> heartbeat over this channel in order to keep the NAPT binding(s) 
> >> active.
> >> 
> >> - one point we skipped is that of NAT detection. You could always 
> >> send heartbeats, regardless of the presence of NAT, but if you use 
> >> the two-port method, you must detect NAT in any case (for reasons 
> >> that will become obvious soon). The way IPsec handled this 
> is to have 
> >> the WTP include it's IP and port in one of the messages 
> (in our case, 
> >> during the JOIN), and having the AC compare this to the 
> adress in the 
> >> packet header; if they differ, the AC must inform the WTP 
> of this in 
> >> the response.
> >> 
> >> - NAT detection may be used as an indicator that heartbeat 
> messages 
> >> are needed. Note that the interval should probably be configurable 
> >> (with sensible defaults),  as there is no standard NAT mapping 
> >> lifetime.
> >> 
> >> Okay, so now we have the control channel. The first data channel 
> >> message must be from a STA trying to associate. The WTP 
> bundles this 
> >> up and sends it to the AC - how does the AC associate this with a 
> >> given WTP? Note that there is no guarantee the data 
> channel will have 
> >> the same source address as the control channel (L3 switching, load 
> >> balancing), so we need a binding mechanism to associate 
> the data and 
> >> control channels, from the AC's perspective.
> >> 
> >> We could do this by placing the same session ID as used for the 
> >> control channel into the data channel capwap header, but 
> this header 
> >> will be encrypted once dtls starts, adding some complexity 
> to packet 
> >> handling. Also, we need to manage heartbeats over this channel as 
> >> well, and since we're doing dtls on this channel, we have 
> to decide 
> >> whether to encrypt these or not. If we don't, we've added new 
> >> processing coplexity on both sides. If we do, we're 
> chewing through 
> >> our counter/iv space, meaning we have to take the 
> heartbeat interval 
> >> into rekey consideration for purposes of lifetime computations.
> >> 
> >> Okay, so clearly, using separate ports has some complexity 
> associated 
> >> with it. What about using a mux header instead? By this, I mean 
> >> adding a field between the udp header and the 'data' 
> (capwap header 
> >> or dtls record layer header) to distinguish the two:
> >> 
> >> +----+-----+------+---------+
> >> |  IP | UDP | mux | data    |
> >> +----+-----+------+---------+
> >> 
> >> Let's say the mux header is 32 bits, and we use only one of these 
> >> (for the time being) to indicate control/data (this is 
> much like the 
> >> lwapp 'c' bit). What are the differences in this approach? 
> Two issues 
> >> have been raised:
> >> 
> >> - it adds 4 bytes to the packet
> >> 
> >> - it is unprotected
> >> 
> >> To the first, I would reply that this is a trade-off, the 
> price you 
> >> pay for greatly reduced complexity. But yes, the cost is 4 bytes
> >> 
> >> To the second point, I would reply that Eric addressed this in the 
> >> security considerations of the lwapp-dtls draft: there are 
> two things 
> >> an adversary might attempt here: converting protected data into 
> >> unprotected data (data channel into control channel), and 
> vice versa.
> >> 
> >> Now, keep in mind that an attacker must be a MiM to do 
> this, implying 
> >> they can insert and delete packets at will anyway.
> >> If the adversary converts a data packet (unencrypted) to a control 
> >> packet, decryption/authentication will fail, and this will be 
> >> detected. If the adversary converts a control packet (encrypted, 
> >> authenticated) to a data packet, it will be interpreted as 
> garbage - 
> >> again, it will be detected.
> >> 
> >> The bottom line: there is no threat here that does not 
> exist in the 
> >> two-port case. They are equivalent in this respect.
> >> 
> >> In the plus column, I think we can say that the mux header 
> approach 
> >> is simpler, in that the NAT-T concerns only apply to one 
> channel, and 
> >> the binding between control and data channels is unambiguous. 
> >> Further, it gives the ability to provide a single 
> de-muxing channel 
> >> in the code for inbound packet handling, which may be 
> advantageous, 
> >> depending on implementation nuances.
> >> 
> >> We decided at our meeting yesterday that for these 
> reasons, the mux 
> >> header approach seems the most sensible. Does anyone object?
> >> 
> >> --Scott
> >> 
> >> _________________________________________________________________
> >> To unsubscribe or modify your subscription options, please visit:
> >> http://lists.frascone.com/mailman/listinfo/capwap
> >> 
> >> Archives: http://lists.frascone.com/pipermail/capwap
> >> 
> 
_________________________________________________________________
To unsubscribe or modify your subscription options, please visit:
http://lists.frascone.com/mailman/listinfo/capwap

Archives: http://lists.frascone.com/pipermail/capwap

---

From: Charles Clancy <[email-masked]>
Date: Thu, 23 Mar 2006 20:15:20 -0500

The MUX header would be necessary if you had a DTLS control channel and 
an unprotected data channel using the *same* UDP port.  It would look 
something like:

+---------+-------------+-------------------------------
| UDP Hdr | MUX Hdr = 1 | DTLS Enc Control Packet ....
+---------+-------------+----------------------

+---------+-------------+---------------------------
| UDP Hdr | MUX Hdr = 2 | Encapsulated Data Packet
+---------+-------------+----------------------

It's basically 1 bit (though 32 bits may be necessary for alignment) 
that says whether the rest of the packet is encrypted or not.

If you DTLS-encrypt both channels, then the MUX header would not be 
necessary.  If you use two UDP channels and have some way to correlate 
data and control channels, then the MUX header is not necessary.  Such 
correlation could be done perhaps with a session ID in the CAPWAP header.

[ t. charles clancy ]--[ [email-masked] ]--[ www.cs.umd.edu/~clancy ]
[ computer science ]-----[ university of maryland | college park ]

---

From: Scott G Kelly <[email-masked]>
Date: Fri, 24 Mar 2006 05:50:48 -0800

> we can even assume it is a given.

Okay, one more time for the people in the back of the room: this has 
absolutely nothing to do with data channel encryption - nothing 
whatsover. I've said that several times now, yet people keep coming back 
to this. This is a waste of energy.

> be done in order to support NAT.

HTTP has nothing to do with this discussion. This has to do with (1) 
managing 2 separate unbound *datagram* channels over NAT-T, and (2) the 
complexity this adds to the state machine. I can re-write a description 
of the problems we'll have to solve with two channel NAT-T again, but 
the rationale is all in the first email in this thread.

The basic function of the mux header is that it allows you to combine 
the two channels over one UDP transport session. That accomplishes three 
things for us: implicit channel binding, elimination of a second 
keepalive timer and associated processing, and simplification of the 
state machine, both with respect to normal processing and error states. 
It's easier to implement and operate.

A mux header does not require DTLS state for data and control to be the 
same - it does not require DTLS state for data - period. It does, 
however, require a unified input routine which looks at the mux header 
and then de-muxes the traffic (to dtls if control, to capwap if data).
Charles correctly describes the packet format in a later email in this 
thread. Assuming you were blocked on a UDP socket read, you would (in 
the generic sense) receive something like this:

+---------+--------------------------------------+
| MUX Hdr | Encapsulated control or Data Packet  |
+---------+--------------------------------------+

Of course, if you want IP header field values, you can get them with the 
appropriate socket calls. Some implementations might instead want to 
have the whole packet, and those implementations could set a pointer to 
the mux header prior to exec'ing the the code that looks a the mux 
header, but either way, here's pseudocode showing where you wind up:

if ( mux header type is control )
{
   if ( dtlsInput(encap'd data) returns error )
     do error handling
   else if ( capwapInput(unencap'd data) returns error )
     do error handling
}
else /* it's a data packet */
{
   if ( capwapInput(unencap'd data) returns error )
     do error handling
}

[there are certainly more efficient ways to code this, but this is aimed 
at clarity]

You presumably have something very much like this in your lwapp 
implementation right now - it looks at the c bit and makes the same sort 
of demux decision, right?

The only drawback I can see is that you can't use the openssl SSL_read() 
call directly with the socket (assuming you use sockets), due to the mux 
header - but it would be straightforward to code an openssl BIO 
extension to allow this if that were really important to someone.

So, once again, let me summarize: using two unbound datagram channels 
greatly complicates things when compared to this approach. You need to 
create a binding between the two channels somehow, you need to manage 
dual keep-alives (one per channel), and there are more error conditions 
to manage in the state machine.

What are the benefits of the two-port approach that outweigh these 
drawbacks?

Scott