mapper.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. package portmapper
  2. import (
  3. "errors"
  4. "fmt"
  5. "net"
  6. "github.com/docker/docker/libnetwork/portallocator"
  7. "github.com/ishidawataru/sctp"
  8. "github.com/sirupsen/logrus"
  9. )
  10. type mapping struct {
  11. proto string
  12. userlandProxy userlandProxy
  13. host net.Addr
  14. container net.Addr
  15. }
  16. // newProxy is used to mock out the proxy server in tests
  17. var newProxy = newProxyCommand
  18. var (
  19. // ErrUnknownBackendAddressType refers to an unknown container or unsupported address type
  20. ErrUnknownBackendAddressType = errors.New("unknown container address type not supported")
  21. // ErrPortMappedForIP refers to a port already mapped to an ip address
  22. ErrPortMappedForIP = errors.New("port is already mapped to ip")
  23. // ErrPortNotMapped refers to an unmapped port
  24. ErrPortNotMapped = errors.New("port is not mapped")
  25. // ErrSCTPAddrNoIP refers to a SCTP address without IP address.
  26. ErrSCTPAddrNoIP = errors.New("sctp address does not contain any IP address")
  27. )
  28. // New returns a new instance of PortMapper
  29. func New(proxyPath string) *PortMapper {
  30. return NewWithPortAllocator(portallocator.Get(), proxyPath)
  31. }
  32. // NewWithPortAllocator returns a new instance of PortMapper which will use the specified PortAllocator
  33. func NewWithPortAllocator(allocator *portallocator.PortAllocator, proxyPath string) *PortMapper {
  34. return &PortMapper{
  35. currentMappings: make(map[string]*mapping),
  36. Allocator: allocator,
  37. proxyPath: proxyPath,
  38. }
  39. }
  40. // Map maps the specified container transport address to the host's network address and transport port
  41. func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, useProxy bool) (host net.Addr, err error) {
  42. return pm.MapRange(container, hostIP, hostPort, hostPort, useProxy)
  43. }
  44. // MapRange maps the specified container transport address to the host's network address and transport port range
  45. func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart, hostPortEnd int, useProxy bool) (host net.Addr, err error) {
  46. pm.lock.Lock()
  47. defer pm.lock.Unlock()
  48. var (
  49. m *mapping
  50. proto string
  51. allocatedHostPort int
  52. )
  53. switch t := container.(type) {
  54. case *net.TCPAddr:
  55. proto = "tcp"
  56. if allocatedHostPort, err = pm.Allocator.RequestPortInRange(hostIP, proto, hostPortStart, hostPortEnd); err != nil {
  57. return nil, err
  58. }
  59. m = &mapping{
  60. proto: proto,
  61. host: &net.TCPAddr{IP: hostIP, Port: allocatedHostPort},
  62. container: container,
  63. }
  64. if useProxy {
  65. m.userlandProxy, err = newProxy(proto, hostIP, allocatedHostPort, t.IP, t.Port, pm.proxyPath)
  66. if err != nil {
  67. return nil, err
  68. }
  69. } else {
  70. m.userlandProxy, err = newDummyProxy(proto, hostIP, allocatedHostPort)
  71. if err != nil {
  72. return nil, err
  73. }
  74. }
  75. case *net.UDPAddr:
  76. proto = "udp"
  77. if allocatedHostPort, err = pm.Allocator.RequestPortInRange(hostIP, proto, hostPortStart, hostPortEnd); err != nil {
  78. return nil, err
  79. }
  80. m = &mapping{
  81. proto: proto,
  82. host: &net.UDPAddr{IP: hostIP, Port: allocatedHostPort},
  83. container: container,
  84. }
  85. if useProxy {
  86. m.userlandProxy, err = newProxy(proto, hostIP, allocatedHostPort, t.IP, t.Port, pm.proxyPath)
  87. if err != nil {
  88. return nil, err
  89. }
  90. } else {
  91. m.userlandProxy, err = newDummyProxy(proto, hostIP, allocatedHostPort)
  92. if err != nil {
  93. return nil, err
  94. }
  95. }
  96. case *sctp.SCTPAddr:
  97. proto = "sctp"
  98. if allocatedHostPort, err = pm.Allocator.RequestPortInRange(hostIP, proto, hostPortStart, hostPortEnd); err != nil {
  99. return nil, err
  100. }
  101. m = &mapping{
  102. proto: proto,
  103. host: &sctp.SCTPAddr{IPAddrs: []net.IPAddr{{IP: hostIP}}, Port: allocatedHostPort},
  104. container: container,
  105. }
  106. if useProxy {
  107. sctpAddr := container.(*sctp.SCTPAddr)
  108. if len(sctpAddr.IPAddrs) == 0 {
  109. return nil, ErrSCTPAddrNoIP
  110. }
  111. m.userlandProxy, err = newProxy(proto, hostIP, allocatedHostPort, sctpAddr.IPAddrs[0].IP, sctpAddr.Port, pm.proxyPath)
  112. if err != nil {
  113. return nil, err
  114. }
  115. } else {
  116. m.userlandProxy, err = newDummyProxy(proto, hostIP, allocatedHostPort)
  117. if err != nil {
  118. return nil, err
  119. }
  120. }
  121. default:
  122. return nil, ErrUnknownBackendAddressType
  123. }
  124. // release the allocated port on any further error during return.
  125. defer func() {
  126. if err != nil {
  127. pm.Allocator.ReleasePort(hostIP, proto, allocatedHostPort)
  128. }
  129. }()
  130. key := getKey(m.host)
  131. if _, exists := pm.currentMappings[key]; exists {
  132. return nil, ErrPortMappedForIP
  133. }
  134. containerIP, containerPort := getIPAndPort(m.container)
  135. if err := pm.AppendForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
  136. return nil, err
  137. }
  138. cleanup := func() error {
  139. // need to undo the iptables rules before we return
  140. m.userlandProxy.Stop()
  141. pm.DeleteForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
  142. if err := pm.Allocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
  143. return err
  144. }
  145. return nil
  146. }
  147. if err := m.userlandProxy.Start(); err != nil {
  148. if err := cleanup(); err != nil {
  149. return nil, fmt.Errorf("Error during port allocation cleanup: %v", err)
  150. }
  151. return nil, err
  152. }
  153. pm.currentMappings[key] = m
  154. return m.host, nil
  155. }
  156. // Unmap removes stored mapping for the specified host transport address
  157. func (pm *PortMapper) Unmap(host net.Addr) error {
  158. pm.lock.Lock()
  159. defer pm.lock.Unlock()
  160. key := getKey(host)
  161. data, exists := pm.currentMappings[key]
  162. if !exists {
  163. return ErrPortNotMapped
  164. }
  165. if data.userlandProxy != nil {
  166. data.userlandProxy.Stop()
  167. }
  168. delete(pm.currentMappings, key)
  169. containerIP, containerPort := getIPAndPort(data.container)
  170. hostIP, hostPort := getIPAndPort(data.host)
  171. if err := pm.DeleteForwardingTableEntry(data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil {
  172. logrus.Errorf("Error on iptables delete: %s", err)
  173. }
  174. switch a := host.(type) {
  175. case *net.TCPAddr:
  176. return pm.Allocator.ReleasePort(a.IP, "tcp", a.Port)
  177. case *net.UDPAddr:
  178. return pm.Allocator.ReleasePort(a.IP, "udp", a.Port)
  179. case *sctp.SCTPAddr:
  180. if len(a.IPAddrs) == 0 {
  181. return ErrSCTPAddrNoIP
  182. }
  183. return pm.Allocator.ReleasePort(a.IPAddrs[0].IP, "sctp", a.Port)
  184. }
  185. return ErrUnknownBackendAddressType
  186. }
  187. // ReMapAll re-applies all port mappings
  188. func (pm *PortMapper) ReMapAll() {
  189. pm.lock.Lock()
  190. defer pm.lock.Unlock()
  191. logrus.Debugln("Re-applying all port mappings.")
  192. for _, data := range pm.currentMappings {
  193. containerIP, containerPort := getIPAndPort(data.container)
  194. hostIP, hostPort := getIPAndPort(data.host)
  195. if err := pm.AppendForwardingTableEntry(data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil {
  196. logrus.Errorf("Error on iptables add: %s", err)
  197. }
  198. }
  199. }
  200. func getKey(a net.Addr) string {
  201. switch t := a.(type) {
  202. case *net.TCPAddr:
  203. return fmt.Sprintf("%s:%d/%s", t.IP.String(), t.Port, "tcp")
  204. case *net.UDPAddr:
  205. return fmt.Sprintf("%s:%d/%s", t.IP.String(), t.Port, "udp")
  206. case *sctp.SCTPAddr:
  207. if len(t.IPAddrs) == 0 {
  208. logrus.Error(ErrSCTPAddrNoIP)
  209. return ""
  210. }
  211. return fmt.Sprintf("%s:%d/%s", t.IPAddrs[0].IP.String(), t.Port, "sctp")
  212. }
  213. return ""
  214. }
  215. func getIPAndPort(a net.Addr) (net.IP, int) {
  216. switch t := a.(type) {
  217. case *net.TCPAddr:
  218. return t.IP, t.Port
  219. case *net.UDPAddr:
  220. return t.IP, t.Port
  221. case *sctp.SCTPAddr:
  222. if len(t.IPAddrs) == 0 {
  223. logrus.Error(ErrSCTPAddrNoIP)
  224. return nil, 0
  225. }
  226. return t.IPAddrs[0].IP, t.Port
  227. }
  228. return nil, 0
  229. }