Subject: [pcp] review of pcp-base-24

From: Iljitsch van Beijnum <[email-masked]>
Date: Mon, 2 Apr 2012 17:38:01 +0200

Here a short^H^H^H^H^H review of the draft. I didn't exhaustively look at all details, though. (Especially the different calculations.) I strongly suspect that additional answers can be found in other PCP wg work and in the previous version discussions, but I didn't look at that because the document needs to stand on its own and have explicit pointers to other work when relevant.

Let me first say that I like this work a lot and I think it uses the right approach and philosophy.

Section 7.3 on options:

Unless I misunderstand this, if an optional option (ha) is present and the server doesn't understand that option, that's ok. But if the server does understand the option, and judges it to be malformed, the server should reject the entire request.

So what can happen now is that client A sends a packet with options X and Y that is handled by server B running version 1 (of the server software, I'm not talking about the protocol version here). Bv1 doesn't understand Y so it handles X and A is mostly happy because it gets a mapping even though some additional feature can't be used. Now B is upgraded to version 2, and Bv2 finds option Y faulty. So now when A does what it always did, but the results are different, and not in a good way.

A might be able to work around this by resubmitting a request with only option X and not option Y, but such behavior is relatively complex and hard to test, so I don't think it's a good solution.

My suggestion: the server silently ignores optional options where the content of the option is malformed and only sends back an error if the option header itself (that needs to be parsable to get to the next option) is malformed, or in the case of mandatory options. In this case, from the client's perspective, the server behavior is the same whether the server doesn't implement an option or the server can't parse the option (because of an issue on either the client or the server).

7.4 on error codes:

I think the NO_RESOURCES error should be agnostic about the well-formedness and validness of the request, an implementation may decide it has no resources to check for these at this time. Many errors are still possible for well-formed and valid requests to servers with ample resources anyway.

8:

Perhaps point out that it's also possible that packets are duplicated in the network relatively easily (on wifi the data packet makes it through but the layer 2 ACK is lost so the packet is retransmitted) so two responses to one request will happen with some regularity.

8.1:

If the client has to explicitly address requests at a server's unicast address, how are clients expected to contact servers in the case of CGN or NAT64? These are multiple hops away and generally not explicitly known to the hosts they serve. Requiring DHCP(v6) options for this discovery is highly problematic in my opinion, because in CGN and NAT64 deployments there will typically be a CPE in the path that would then have to request the new DHCP option on its WAN side and advertise it on its LAN side. (Assuming this device supports DHCPv6 on both sides in the first place!) This is especially problematic because the PCP doesn't otherwise require the cooperation of such a CPE in at least the NAT64 case. Also, a PCP client could presumably be implemented as part of an application on operating systems that don't support a new DHCP option, and applications may not be in the position to add this support.

I know we had a hard time gaining consensus on NAT64 prefix discovery mechanisms, which is basically the same problem. But getting this right would make PCP more useful with the CGN/NAT64 use cases by a huge margin.

I would even go so far as to suggest that clients should have the option to learn one or more PCP server addresses through manual configuration as a last resort.

8.4:

"IPv6 addresses
   without global reachability (e.g., ULA [
RFC4193
]), SHOULD NOT be used
   as the source interface when generating a PCP request."

This of course makes it impossible to have PCP work with IPv6 NAT, for better or for worse.

10.2:

   An application that is using the same port for outgoing connections
   as well as incoming connections MUST first signal its operation of a
   server using the PCP MAP Opcode, as described in 
Section 11
, and
   receive a positive PCP response before it sends any packets from that
   port.

As per the discussion follow that paragraph, this optimizes for the case where the application runs on a host residing behind a PCP-capable NAT/firewall at the expense of the cases where a NAT/firewall isn't present or is present but doesn't support either PCP nor endpoint independent mappings. I don't think that's necessarily the right tradeoff. But, more importantly, I don't understand the MUST here. Can someone explain this?

It's certainly conceivable that an application could get a strong hint that PCP is either supported or not supported, and optimize its behavior accordingly. Also, certain applications may suffer from an initial delay much more than from the situation where initially incoming sessions can't be established, and thus prefer to initiate outgoing sessions without waiting for PCP mappings. Further, in the case of firewalls there should be no issues creating a mapping after setting up a session, because port numbers will not be changed.

For IPv4 the difference between the NAT and firewall cases can be determined with a high degree of confidence by the use of RFC 1918 addresses, while in the case of NAT64 endpoint independent mappings are specified in the NAT64 spec and as per the above, IPv6 NAT isn't supported by PCP anyway. So: RFC 1918 -> SHOULD PCP MAP first, ! RFC 1918 -> SHOULD NOT PCP MAP first.

11.1:

   Suggested External IP Address:  Suggested external IPv4 or IPv6
      address.  This is useful for refreshing a mapping, especially
      after the PCP server loses state.  If the PCP client does not know
      the external address, or does not have a preference, it MUST use
      the address-family-specific all-zeroes address (see 
Section 5).

I wonder if it could be useful to have the ability to specify address family agnostic mappings? (I'm starting to imagine NAT46 functionality...)

   Lifetime (in common header):  On an error response, this indicates
      how long clients should assume they'll get the same error response
      from the PCP server if they repeat the same request.  On a success
      response, this indicates the lifetime for this mapping, in
      seconds.

Ii think this needs a default that is used when implementers have no information one way or the other about what value to use here. 5 minutes? 10? 30?

11.5:

   o  If both the internal port and protocol are zero, it indicates a
      request to delete all mappings for this Internal Address for all
      transport protocols.  This is useful when a host reboots or joins
      a new network, to clear out prior stale state from the NAT gateway
      before beginning to install new mappings.

What if multiple PCP client implementations/instances live on the same host? Unless they compete for the same mappings, that should work without trouble, but if one of them were to issue a request as per the above, that would be very destructive. There is also potential for DoS by other hosts on the same subnet.

I would feel more comfortable with this if rather than removing mappings, the server reduces the remaining lifetime of the existing mappings and then sends notifications to the clients that requested these mappings, so that they can refresh them if they're still desired.

I don't think this operation is ever appropriate on client implementations that aren't part of the operating system.

11.6:

I think it would make sense to recommend that clients request mappings with lifetimes that match the lifetimes of the addresses they obtained through DHCP and/or stateless autoconfig. This way, when an address expires, the mappings expire at about the same time, avoiding issues if another host subsequently obtains that address.

Note that one source of regular address changes is the use of RFC 4941 temporary / privacy addresses. Of course in the IPv6 case there are generally no issues with ports not being available so a deprecated and a new temporary address could exist side by side and use a mapping to the same port without issue.

13.2:

   PCP servers MAY choose to rate-limit their handling of PREFER_FAILURE
   requests, to protect themselves from a rapid flurry of 65535
   consecutive PREFER_FAILURE requests from clients probing to discover
   which external ports are available.

Hm, this reads as an implementation suggestion to clients... Maybe point out a better way to obtain a port.

13.3.  FILTER Option for MAP Opcode

This is a DoS attack waiting to happen. I don't think it's a good idea to allow a feature like this with at least some kind of return routability check. And even then, one application with little or no privileges could make the entire internet unreachable for the entire host.

15.2, 15.3, 15.3.1, 15.3.2:

   This section provides...

Please don't repeat this sentence or a very similar one over and over. Once for the entire section 15 is enough.

15.3.2:

   If the client wishes to check the PCP server's Epoch Time, it
   sends a PCP request for any one of the client's mappings.  This will
   return the current Epoch Time value.

Wouldn't it be better if there was a separate message for doing this? That would save the server from consulting its mapping state, allowing it to answer such requests very quickly.

Does it make sense to reset the epoch when a NAT device loses its external address?

17.1.1:

   o  If you allow multiple administrative domains to send PCP requests

Addressing the reader is uncommon in RFCs.

18.1:

   PCP will use ports 5350 and 5351 (currently assigned by IANA to NAT-
   PMP [
I-D.cheshire-nat-pmp]).

So what happens when a NAT-PMP client and a PCP server or a PCP client and NAT-PMP server end up talking to each other? Answer: mention appendix A here.

What about the NAT64 case where mappings are only relevant to/from IPv4 space mapped by the NAT64, and presumably not to/from other IPv6 space? Is it useful for the server to indicate that the mappings only apply to a certain subset of destinations, or should clients simply always request mappings and then proceed to communicate whether they get the mappings or not? In support of the former: it may be useful to know that STUN-like mechanisms are necessary for some, but unnecessary for other destinations , for instance. Also, if a NAT64 user wants to use a STUN-like mechanism to learn its externally visible IP address, it would be good to know which prefix represents the IPv4 address space so it knows destinations in that prefix see something other than destinations outside that prefix.