nat.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. package vnet
  2. import (
  3. "errors"
  4. "fmt"
  5. "net"
  6. "sync"
  7. "time"
  8. "github.com/pion/logging"
  9. )
  10. var (
  11. errNATRequriesMapping = errors.New("1:1 NAT requires more than one mapping")
  12. errMismatchLengthIP = errors.New("length mismtach between mappedIPs and localIPs")
  13. errNonUDPTranslationNotSupported = errors.New("non-udp translation is not supported yet")
  14. errNoAssociatedLocalAddress = errors.New("no associated local address")
  15. errNoNATBindingFound = errors.New("no NAT binding found")
  16. errHasNoPermission = errors.New("has no permission")
  17. )
  18. // EndpointDependencyType defines a type of behavioral dependendency on the
  19. // remote endpoint's IP address or port number. This is used for the two
  20. // kinds of behaviors:
  21. // - Port mapping behavior
  22. // - Filtering behavior
  23. // See: https://tools.ietf.org/html/rfc4787
  24. type EndpointDependencyType uint8
  25. const (
  26. // EndpointIndependent means the behavior is independent of the endpoint's address or port
  27. EndpointIndependent EndpointDependencyType = iota
  28. // EndpointAddrDependent means the behavior is dependent on the endpoint's address
  29. EndpointAddrDependent
  30. // EndpointAddrPortDependent means the behavior is dependent on the endpoint's address and port
  31. EndpointAddrPortDependent
  32. )
  33. // NATMode defines basic behavior of the NAT
  34. type NATMode uint8
  35. const (
  36. // NATModeNormal means the NAT behaves as a standard NAPT (RFC 2663).
  37. NATModeNormal NATMode = iota
  38. // NATModeNAT1To1 exhibits 1:1 DNAT where the external IP address is statically mapped to
  39. // a specific local IP address with port number is preserved always between them.
  40. // When this mode is selected, MappingBehavior, FilteringBehavior, PortPreservation and
  41. // MappingLifeTime of NATType are ignored.
  42. NATModeNAT1To1
  43. )
  44. const (
  45. defaultNATMappingLifeTime = 30 * time.Second
  46. )
  47. // NATType has a set of parameters that define the behavior of NAT.
  48. type NATType struct {
  49. Mode NATMode
  50. MappingBehavior EndpointDependencyType
  51. FilteringBehavior EndpointDependencyType
  52. Hairpining bool // Not implemented yet
  53. PortPreservation bool // Not implemented yet
  54. MappingLifeTime time.Duration
  55. }
  56. type natConfig struct {
  57. name string
  58. natType NATType
  59. mappedIPs []net.IP // mapped IPv4
  60. localIPs []net.IP // local IPv4, required only when the mode is NATModeNAT1To1
  61. loggerFactory logging.LoggerFactory
  62. }
  63. type mapping struct {
  64. proto string // "udp" or "tcp"
  65. local string // "<local-ip>:<local-port>"
  66. mapped string // "<mapped-ip>:<mapped-port>"
  67. bound string // key: "[<remote-ip>[:<remote-port>]]"
  68. filters map[string]struct{} // key: "[<remote-ip>[:<remote-port>]]"
  69. expires time.Time // time to expire
  70. }
  71. type networkAddressTranslator struct {
  72. name string
  73. natType NATType
  74. mappedIPs []net.IP // mapped IPv4
  75. localIPs []net.IP // local IPv4, required only when the mode is NATModeNAT1To1
  76. outboundMap map[string]*mapping // key: "<proto>:<local-ip>:<local-port>[:remote-ip[:remote-port]]
  77. inboundMap map[string]*mapping // key: "<proto>:<mapped-ip>:<mapped-port>"
  78. udpPortCounter int
  79. mutex sync.RWMutex
  80. log logging.LeveledLogger
  81. }
  82. func newNAT(config *natConfig) (*networkAddressTranslator, error) {
  83. natType := config.natType
  84. if natType.Mode == NATModeNAT1To1 {
  85. // 1:1 NAT behavior
  86. natType.MappingBehavior = EndpointIndependent
  87. natType.FilteringBehavior = EndpointIndependent
  88. natType.PortPreservation = true
  89. natType.MappingLifeTime = 0
  90. if len(config.mappedIPs) == 0 {
  91. return nil, errNATRequriesMapping
  92. }
  93. if len(config.mappedIPs) != len(config.localIPs) {
  94. return nil, errMismatchLengthIP
  95. }
  96. } else {
  97. // Normal (NAPT) behavior
  98. natType.Mode = NATModeNormal
  99. if natType.MappingLifeTime == 0 {
  100. natType.MappingLifeTime = defaultNATMappingLifeTime
  101. }
  102. }
  103. return &networkAddressTranslator{
  104. name: config.name,
  105. natType: natType,
  106. mappedIPs: config.mappedIPs,
  107. localIPs: config.localIPs,
  108. outboundMap: map[string]*mapping{},
  109. inboundMap: map[string]*mapping{},
  110. log: config.loggerFactory.NewLogger("vnet"),
  111. }, nil
  112. }
  113. func (n *networkAddressTranslator) getPairedMappedIP(locIP net.IP) net.IP {
  114. for i, ip := range n.localIPs {
  115. if ip.Equal(locIP) {
  116. return n.mappedIPs[i]
  117. }
  118. }
  119. return nil
  120. }
  121. func (n *networkAddressTranslator) getPairedLocalIP(mappedIP net.IP) net.IP {
  122. for i, ip := range n.mappedIPs {
  123. if ip.Equal(mappedIP) {
  124. return n.localIPs[i]
  125. }
  126. }
  127. return nil
  128. }
  129. func (n *networkAddressTranslator) translateOutbound(from Chunk) (Chunk, error) {
  130. n.mutex.Lock()
  131. defer n.mutex.Unlock()
  132. to := from.Clone()
  133. if from.Network() == udpString {
  134. if n.natType.Mode == NATModeNAT1To1 {
  135. // 1:1 NAT behavior
  136. srcAddr := from.SourceAddr().(*net.UDPAddr) //nolint:forcetypeassert
  137. srcIP := n.getPairedMappedIP(srcAddr.IP)
  138. if srcIP == nil {
  139. n.log.Debugf("[%s] drop outbound chunk %s with not route", n.name, from.String())
  140. return nil, nil // nolint:nilnil
  141. }
  142. srcPort := srcAddr.Port
  143. if err := to.setSourceAddr(fmt.Sprintf("%s:%d", srcIP.String(), srcPort)); err != nil {
  144. return nil, err
  145. }
  146. } else {
  147. // Normal (NAPT) behavior
  148. var bound, filterKey string
  149. switch n.natType.MappingBehavior {
  150. case EndpointIndependent:
  151. bound = ""
  152. case EndpointAddrDependent:
  153. bound = from.getDestinationIP().String()
  154. case EndpointAddrPortDependent:
  155. bound = from.DestinationAddr().String()
  156. }
  157. switch n.natType.FilteringBehavior {
  158. case EndpointIndependent:
  159. filterKey = ""
  160. case EndpointAddrDependent:
  161. filterKey = from.getDestinationIP().String()
  162. case EndpointAddrPortDependent:
  163. filterKey = from.DestinationAddr().String()
  164. }
  165. oKey := fmt.Sprintf("udp:%s:%s", from.SourceAddr().String(), bound)
  166. m := n.findOutboundMapping(oKey)
  167. if m == nil {
  168. // Create a new mapping
  169. mappedPort := 0xC000 + n.udpPortCounter
  170. n.udpPortCounter++
  171. m = &mapping{
  172. proto: from.SourceAddr().Network(),
  173. local: from.SourceAddr().String(),
  174. bound: bound,
  175. mapped: fmt.Sprintf("%s:%d", n.mappedIPs[0].String(), mappedPort),
  176. filters: map[string]struct{}{},
  177. expires: time.Now().Add(n.natType.MappingLifeTime),
  178. }
  179. n.outboundMap[oKey] = m
  180. iKey := fmt.Sprintf("udp:%s", m.mapped)
  181. n.log.Debugf("[%s] created a new NAT binding oKey=%s iKey=%s",
  182. n.name,
  183. oKey,
  184. iKey)
  185. m.filters[filterKey] = struct{}{}
  186. n.log.Debugf("[%s] permit access from %s to %s", n.name, filterKey, m.mapped)
  187. n.inboundMap[iKey] = m
  188. } else if _, ok := m.filters[filterKey]; !ok {
  189. n.log.Debugf("[%s] permit access from %s to %s", n.name, filterKey, m.mapped)
  190. m.filters[filterKey] = struct{}{}
  191. }
  192. if err := to.setSourceAddr(m.mapped); err != nil {
  193. return nil, err
  194. }
  195. }
  196. n.log.Debugf("[%s] translate outbound chunk from %s to %s", n.name, from.String(), to.String())
  197. return to, nil
  198. }
  199. return nil, errNonUDPTranslationNotSupported
  200. }
  201. func (n *networkAddressTranslator) translateInbound(from Chunk) (Chunk, error) {
  202. n.mutex.Lock()
  203. defer n.mutex.Unlock()
  204. to := from.Clone()
  205. if from.Network() == udpString {
  206. if n.natType.Mode == NATModeNAT1To1 {
  207. // 1:1 NAT behavior
  208. dstAddr := from.DestinationAddr().(*net.UDPAddr) //nolint:forcetypeassert
  209. dstIP := n.getPairedLocalIP(dstAddr.IP)
  210. if dstIP == nil {
  211. return nil, fmt.Errorf("drop %s as %w", from.String(), errNoAssociatedLocalAddress)
  212. }
  213. dstPort := from.DestinationAddr().(*net.UDPAddr).Port //nolint:forcetypeassert
  214. if err := to.setDestinationAddr(fmt.Sprintf("%s:%d", dstIP, dstPort)); err != nil {
  215. return nil, err
  216. }
  217. } else {
  218. // Normal (NAPT) behavior
  219. iKey := fmt.Sprintf("udp:%s", from.DestinationAddr().String())
  220. m := n.findInboundMapping(iKey)
  221. if m == nil {
  222. return nil, fmt.Errorf("drop %s as %w", from.String(), errNoNATBindingFound)
  223. }
  224. var filterKey string
  225. switch n.natType.FilteringBehavior {
  226. case EndpointIndependent:
  227. filterKey = ""
  228. case EndpointAddrDependent:
  229. filterKey = from.getSourceIP().String()
  230. case EndpointAddrPortDependent:
  231. filterKey = from.SourceAddr().String()
  232. }
  233. if _, ok := m.filters[filterKey]; !ok {
  234. return nil, fmt.Errorf("drop %s as the remote %s %w", from.String(), filterKey, errHasNoPermission)
  235. }
  236. // See RFC 4847 Section 4.3. Mapping Refresh
  237. // a) Inbound refresh may be useful for applications with no outgoing
  238. // UDP traffic. However, allowing inbound refresh may allow an
  239. // external attacker or misbehaving application to keep a mapping
  240. // alive indefinitely. This may be a security risk. Also, if the
  241. // process is repeated with different ports, over time, it could
  242. // use up all the ports on the NAT.
  243. if err := to.setDestinationAddr(m.local); err != nil {
  244. return nil, err
  245. }
  246. }
  247. n.log.Debugf("[%s] translate inbound chunk from %s to %s", n.name, from.String(), to.String())
  248. return to, nil
  249. }
  250. return nil, errNonUDPTranslationNotSupported
  251. }
  252. // caller must hold the mutex
  253. func (n *networkAddressTranslator) findOutboundMapping(oKey string) *mapping {
  254. now := time.Now()
  255. m, ok := n.outboundMap[oKey]
  256. if ok {
  257. // check if this mapping is expired
  258. if now.After(m.expires) {
  259. n.removeMapping(m)
  260. m = nil // expired
  261. } else {
  262. m.expires = time.Now().Add(n.natType.MappingLifeTime)
  263. }
  264. }
  265. return m
  266. }
  267. // caller must hold the mutex
  268. func (n *networkAddressTranslator) findInboundMapping(iKey string) *mapping {
  269. now := time.Now()
  270. m, ok := n.inboundMap[iKey]
  271. if !ok {
  272. return nil
  273. }
  274. // check if this mapping is expired
  275. if now.After(m.expires) {
  276. n.removeMapping(m)
  277. return nil
  278. }
  279. return m
  280. }
  281. // caller must hold the mutex
  282. func (n *networkAddressTranslator) removeMapping(m *mapping) {
  283. oKey := fmt.Sprintf("%s:%s:%s", m.proto, m.local, m.bound)
  284. iKey := fmt.Sprintf("%s:%s", m.proto, m.mapped)
  285. delete(n.outboundMap, oKey)
  286. delete(n.inboundMap, iKey)
  287. }