port_mapping.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. // +build solaris
  2. package bridge
  3. import (
  4. "bytes"
  5. "errors"
  6. "fmt"
  7. "net"
  8. "os"
  9. "os/exec"
  10. "github.com/Sirupsen/logrus"
  11. "github.com/docker/libnetwork/types"
  12. )
  13. var (
  14. defaultBindingIP = net.IPv4(0, 0, 0, 0)
  15. )
  16. const (
  17. maxAllocatePortAttempts = 10
  18. )
  19. func addPFRules(epid, bindIntf string, bs []types.PortBinding) {
  20. var id string
  21. if len(epid) > 12 {
  22. id = epid[:12]
  23. } else {
  24. id = epid
  25. }
  26. fname := "/var/lib/docker/network/files/pf." + id
  27. f, err := os.OpenFile(fname,
  28. os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
  29. if err != nil {
  30. logrus.Warn("cannot open temp pf file")
  31. return
  32. }
  33. for _, b := range bs {
  34. r := fmt.Sprintf(
  35. "pass in on %s proto %s from any to (%s) "+
  36. "port %d rdr-to %s port %d\n", bindIntf,
  37. b.Proto.String(), bindIntf, b.HostPort,
  38. b.IP.String(), b.Port)
  39. _, err = f.WriteString(r)
  40. if err != nil {
  41. logrus.Warnf("cannot write firewall rules to %s: %v", fname, err)
  42. }
  43. }
  44. f.Close()
  45. anchor := fmt.Sprintf("_auto/docker/ep%s", id)
  46. err = exec.Command("/usr/sbin/pfctl", "-a", anchor, "-f", fname).Run()
  47. if err != nil {
  48. logrus.Warnf("failed to add firewall rules: %v", err)
  49. }
  50. os.Remove(fname)
  51. }
  52. func removePFRules(epid string) {
  53. var id string
  54. if len(epid) > 12 {
  55. id = epid[:12]
  56. } else {
  57. id = epid
  58. }
  59. anchor := fmt.Sprintf("_auto/docker/ep%s", id)
  60. err := exec.Command("/usr/sbin/pfctl", "-a", anchor, "-F", "all").Run()
  61. if err != nil {
  62. logrus.Warnf("failed to remove firewall rules: %v", err)
  63. }
  64. }
  65. func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, bindIntf string, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
  66. if ep.extConnConfig == nil || ep.extConnConfig.PortBindings == nil {
  67. return nil, nil
  68. }
  69. defHostIP := defaultBindingIP
  70. if reqDefBindIP != nil {
  71. defHostIP = reqDefBindIP
  72. }
  73. bs, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, bindIntf, ep.addr.IP, defHostIP, ulPxyEnabled)
  74. if err != nil {
  75. return nil, err
  76. }
  77. // Add PF rules for port bindings, if any
  78. if len(bs) > 0 {
  79. addPFRules(ep.id, bindIntf, bs)
  80. }
  81. return bs, err
  82. }
  83. func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, bindIntf string, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
  84. bs := make([]types.PortBinding, 0, len(bindings))
  85. for _, c := range bindings {
  86. b := c.GetCopy()
  87. if err := n.allocatePort(&b, containerIP, defHostIP); err != nil {
  88. // On allocation failure,release previously
  89. // allocated ports. On cleanup error, just log
  90. // a warning message
  91. if cuErr := n.releasePortsInternal(bs); cuErr != nil {
  92. logrus.Warnf("Upon allocation failure "+
  93. "for %v, failed to clear previously "+
  94. "allocated port bindings: %v", b, cuErr)
  95. }
  96. return nil, err
  97. }
  98. bs = append(bs, b)
  99. }
  100. return bs, nil
  101. }
  102. func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP) error {
  103. var (
  104. host net.Addr
  105. err error
  106. )
  107. // Store the container interface address in the operational binding
  108. bnd.IP = containerIP
  109. // Adjust the host address in the operational binding
  110. if len(bnd.HostIP) == 0 {
  111. bnd.HostIP = defHostIP
  112. }
  113. // Adjust HostPortEnd if this is not a range.
  114. if bnd.HostPortEnd == 0 {
  115. bnd.HostPortEnd = bnd.HostPort
  116. }
  117. // Construct the container side transport address
  118. container, err := bnd.ContainerAddr()
  119. if err != nil {
  120. return err
  121. }
  122. // Try up to maxAllocatePortAttempts times to get a port that's
  123. // not already allocated.
  124. for i := 0; i < maxAllocatePortAttempts; i++ {
  125. if host, err = n.portMapper.MapRange(container, bnd.HostIP,
  126. int(bnd.HostPort), int(bnd.HostPortEnd), false); err == nil {
  127. break
  128. }
  129. // There is no point in immediately retrying to map an
  130. // explicitly chosen port.
  131. if bnd.HostPort != 0 {
  132. logrus.Warnf(
  133. "Failed to allocate and map port %d-%d: %s",
  134. bnd.HostPort, bnd.HostPortEnd, err)
  135. break
  136. }
  137. logrus.Warnf("Failed to allocate and map port: %s, retry: %d",
  138. err, i+1)
  139. }
  140. if err != nil {
  141. return err
  142. }
  143. // Save the host port (regardless it was or not specified in the
  144. // binding)
  145. switch netAddr := host.(type) {
  146. case *net.TCPAddr:
  147. bnd.HostPort = uint16(host.(*net.TCPAddr).Port)
  148. return nil
  149. case *net.UDPAddr:
  150. bnd.HostPort = uint16(host.(*net.UDPAddr).Port)
  151. return nil
  152. default:
  153. // For completeness
  154. return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr))
  155. }
  156. }
  157. func (n *bridgeNetwork) releasePorts(ep *bridgeEndpoint) error {
  158. err := n.releasePortsInternal(ep.portMapping)
  159. if err != nil {
  160. return nil
  161. }
  162. // remove rules if there are any port mappings
  163. if len(ep.portMapping) > 0 {
  164. removePFRules(ep.id)
  165. }
  166. return nil
  167. }
  168. func (n *bridgeNetwork) releasePortsInternal(bindings []types.PortBinding) error {
  169. var errorBuf bytes.Buffer
  170. // Attempt to release all port bindings, do not stop on failure
  171. for _, m := range bindings {
  172. if err := n.releasePort(m); err != nil {
  173. errorBuf.WriteString(
  174. fmt.Sprintf(
  175. "\ncould not release %v because of %v",
  176. m, err))
  177. }
  178. }
  179. if errorBuf.Len() != 0 {
  180. return errors.New(errorBuf.String())
  181. }
  182. return nil
  183. }
  184. func (n *bridgeNetwork) releasePort(bnd types.PortBinding) error {
  185. // Construct the host side transport address
  186. host, err := bnd.HostAddr()
  187. if err != nil {
  188. return err
  189. }
  190. return n.portMapper.Unmap(host)
  191. }