port.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /*
  2. Copyright 2020 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package net
  14. import (
  15. "fmt"
  16. "net"
  17. "strconv"
  18. "strings"
  19. )
  20. // Protocol is a network protocol support by LocalPort.
  21. type Protocol string
  22. // Constants for valid protocols:
  23. const (
  24. TCP Protocol = "TCP"
  25. UDP Protocol = "UDP"
  26. )
  27. // LocalPort represents an IP address and port pair along with a protocol
  28. // and potentially a specific IP family.
  29. // A LocalPort can be opened and subsequently closed.
  30. type LocalPort struct {
  31. // Description is an arbitrary string.
  32. Description string
  33. // IP is the IP address part of a given local port.
  34. // If this string is empty, the port binds to all local IP addresses.
  35. IP string
  36. // If IPFamily is not empty, the port binds only to addresses of this
  37. // family.
  38. // IF empty along with IP, bind to local addresses of any family.
  39. IPFamily IPFamily
  40. // Port is the port number.
  41. // A value of 0 causes a port to be automatically chosen.
  42. Port int
  43. // Protocol is the protocol, e.g. TCP
  44. Protocol Protocol
  45. }
  46. // NewLocalPort returns a LocalPort instance and ensures IPFamily and IP are
  47. // consistent and that the given protocol is valid.
  48. func NewLocalPort(desc, ip string, ipFamily IPFamily, port int, protocol Protocol) (*LocalPort, error) {
  49. if protocol != TCP && protocol != UDP {
  50. return nil, fmt.Errorf("Unsupported protocol %s", protocol)
  51. }
  52. if ipFamily != IPFamilyUnknown && ipFamily != IPv4 && ipFamily != IPv6 {
  53. return nil, fmt.Errorf("Invalid IP family %s", ipFamily)
  54. }
  55. if ip != "" {
  56. parsedIP := ParseIPSloppy(ip)
  57. if parsedIP == nil {
  58. return nil, fmt.Errorf("invalid ip address %s", ip)
  59. }
  60. if ipFamily != IPFamilyUnknown {
  61. if IPFamily(parsedIP) != ipFamily {
  62. return nil, fmt.Errorf("ip address and family mismatch %s, %s", ip, ipFamily)
  63. }
  64. }
  65. }
  66. return &LocalPort{Description: desc, IP: ip, IPFamily: ipFamily, Port: port, Protocol: protocol}, nil
  67. }
  68. func (lp *LocalPort) String() string {
  69. ipPort := net.JoinHostPort(lp.IP, strconv.Itoa(lp.Port))
  70. return fmt.Sprintf("%q (%s/%s%s)", lp.Description, ipPort, strings.ToLower(string(lp.Protocol)), lp.IPFamily)
  71. }
  72. // Closeable closes an opened LocalPort.
  73. type Closeable interface {
  74. Close() error
  75. }
  76. // PortOpener can open a LocalPort and allows later closing it.
  77. type PortOpener interface {
  78. OpenLocalPort(lp *LocalPort) (Closeable, error)
  79. }
  80. type listenPortOpener struct{}
  81. // ListenPortOpener opens ports by calling bind() and listen().
  82. var ListenPortOpener listenPortOpener
  83. // OpenLocalPort holds the given local port open.
  84. func (l *listenPortOpener) OpenLocalPort(lp *LocalPort) (Closeable, error) {
  85. return openLocalPort(lp)
  86. }
  87. func openLocalPort(lp *LocalPort) (Closeable, error) {
  88. var socket Closeable
  89. hostPort := net.JoinHostPort(lp.IP, strconv.Itoa(lp.Port))
  90. switch lp.Protocol {
  91. case TCP:
  92. network := "tcp" + string(lp.IPFamily)
  93. listener, err := net.Listen(network, hostPort)
  94. if err != nil {
  95. return nil, err
  96. }
  97. socket = listener
  98. case UDP:
  99. network := "udp" + string(lp.IPFamily)
  100. addr, err := net.ResolveUDPAddr(network, hostPort)
  101. if err != nil {
  102. return nil, err
  103. }
  104. conn, err := net.ListenUDP(network, addr)
  105. if err != nil {
  106. return nil, err
  107. }
  108. socket = conn
  109. default:
  110. return nil, fmt.Errorf("unknown protocol %q", lp.Protocol)
  111. }
  112. return socket, nil
  113. }