64 lines
1.2 KiB
Go
64 lines
1.2 KiB
Go
package portforward
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
var ErrInvalidPortSpec = errors.New("invalid port-forwarding specification")
|
|
|
|
type PortSpec struct {
|
|
LocalPort uint16
|
|
RemotePort uint16
|
|
}
|
|
|
|
func NewPortSpec(portSpecRaw string) (*PortSpec, error) {
|
|
splits := strings.Split(portSpecRaw, ":")
|
|
|
|
switch len(splits) {
|
|
case 1:
|
|
remotePort, err := parsePort(splits[0])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &PortSpec{
|
|
LocalPort: 0,
|
|
RemotePort: remotePort,
|
|
}, nil
|
|
case 2:
|
|
localPort, err := parsePort(splits[0])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
remotePort, err := parsePort(splits[1])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &PortSpec{
|
|
LocalPort: localPort,
|
|
RemotePort: remotePort,
|
|
}, nil
|
|
default:
|
|
return nil, fmt.Errorf("%w: expected 1 or 2 components delimited by \":\", found %d",
|
|
ErrInvalidPortSpec, len(splits))
|
|
}
|
|
}
|
|
|
|
func parsePort(s string) (uint16, error) {
|
|
port, err := strconv.ParseUint(s, 10, 16)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
if port < 1 || port > 65535 {
|
|
return 0, fmt.Errorf("%w: only ports in range [1, 65535] are allowed", ErrInvalidPortSpec)
|
|
}
|
|
|
|
return uint16(port), nil
|
|
}
|