A cheat sheet for NAT types

full cone NAT = network traffic-initiated automatic port-forwarding managed by the kernel
xx-restricted cone NAT = traffic-initiated automatic port-forwarding with firewall implemented in someways

symmetric NAT != port-forwarding
The NAT device will also take the outer tuple(source host: port) into account upon receipt, besides the NAT port itself.
Consequently, a symmetric NAT can map a single NAT port to multiple inner tuples(destination host: port) based on incoming packets' outer tuples(and the NAT port, of course).

The difference:
cone NAT/port-forwarding = one-to-one mapping (NAT port, inner tuple)
symmetric NAT = one-to-one mapping (NAT port && outer tuple, inner tuple)

Is it possible to do a symmetric-to-symmetric UDP hole punching?

Symmetric-to-symmetric NAT traverse is still possible by guessing or oracle, whatever you like, but only if there is a predictable pattern, such as a linear increase, in the NAT ports allocated on both sides.

There are always some NAT behaviours hard to fit into any classical NAT category proposed by rfc3489 (i.e. various cones/symmetric), why?

With tricks implemented, we can send packets from a different source outside the LAN to a symmetric NATed socket behind the NAT (i.e. Linux's Netfilter with several additional rules in place, such as DMZ or DNAT rules, which leads to a "full cone" test result using classical STUN[rfc3489]).
However, port allocation behaviour is somewhat ambiguous in a couple of NAT implements; Netfilter is such a classic example. Technically, we can never say for sure using merely STUN if the outer port allocation on NAT is, in fact, always fixed or mutable for the same tuple inside the LAN. Consequently, any "cone NAT" device tested using STUN methodology could turn out to be a "symmetric NAT in disguise" in the end. We never know.