blob: 7b6eca89321ac127605a06dfa55c7a534db8cfeb [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001/*
2Copyright 2015 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package net
18
19import (
20 "fmt"
21 "strconv"
22 "strings"
23)
24
25// PortRange represents a range of TCP/UDP ports. To represent a single port,
26// set Size to 1.
27type PortRange struct {
28 Base int
29 Size int
30}
31
32// Contains tests whether a given port falls within the PortRange.
33func (pr *PortRange) Contains(p int) bool {
34 return (p >= pr.Base) && ((p - pr.Base) < pr.Size)
35}
36
37// String converts the PortRange to a string representation, which can be
38// parsed by PortRange.Set or ParsePortRange.
39func (pr PortRange) String() string {
40 if pr.Size == 0 {
41 return ""
42 }
43 return fmt.Sprintf("%d-%d", pr.Base, pr.Base+pr.Size-1)
44}
45
46// Set parses a string of the form "value", "min-max", or "min+offset", inclusive at both ends, and
47// sets the PortRange from it. This is part of the flag.Value and pflag.Value
48// interfaces.
49func (pr *PortRange) Set(value string) error {
50 const (
51 SinglePortNotation = 1 << iota
52 HyphenNotation
53 PlusNotation
54 )
55
56 value = strings.TrimSpace(value)
57 hyphenIndex := strings.Index(value, "-")
58 plusIndex := strings.Index(value, "+")
59
60 if value == "" {
61 pr.Base = 0
62 pr.Size = 0
63 return nil
64 }
65
66 var err error
67 var low, high int
68 var notation int
69
70 if plusIndex == -1 && hyphenIndex == -1 {
71 notation |= SinglePortNotation
72 }
73 if hyphenIndex != -1 {
74 notation |= HyphenNotation
75 }
76 if plusIndex != -1 {
77 notation |= PlusNotation
78 }
79
80 switch notation {
81 case SinglePortNotation:
82 var port int
83 port, err = strconv.Atoi(value)
84 if err != nil {
85 return err
86 }
87 low = port
88 high = port
89 case HyphenNotation:
90 low, err = strconv.Atoi(value[:hyphenIndex])
91 if err != nil {
92 return err
93 }
94 high, err = strconv.Atoi(value[hyphenIndex+1:])
95 if err != nil {
96 return err
97 }
98 case PlusNotation:
99 var offset int
100 low, err = strconv.Atoi(value[:plusIndex])
101 if err != nil {
102 return err
103 }
104 offset, err = strconv.Atoi(value[plusIndex+1:])
105 if err != nil {
106 return err
107 }
108 high = low + offset
109 default:
110 return fmt.Errorf("unable to parse port range: %s", value)
111 }
112
113 if low > 65535 || high > 65535 {
114 return fmt.Errorf("the port range cannot be greater than 65535: %s", value)
115 }
116
117 if high < low {
118 return fmt.Errorf("end port cannot be less than start port: %s", value)
119 }
120
121 pr.Base = low
122 pr.Size = 1 + high - low
123 return nil
124}
125
126// Type returns a descriptive string about this type. This is part of the
127// pflag.Value interface.
128func (*PortRange) Type() string {
129 return "portRange"
130}
131
132// ParsePortRange parses a string of the form "min-max", inclusive at both
133// ends, and initializs a new PortRange from it.
134func ParsePortRange(value string) (*PortRange, error) {
135 pr := &PortRange{}
136 err := pr.Set(value)
137 if err != nil {
138 return nil, err
139 }
140 return pr, nil
141}
142
143func ParsePortRangeOrDie(value string) *PortRange {
144 pr, err := ParsePortRange(value)
145 if err != nil {
146 panic(fmt.Sprintf("couldn't parse port range %q: %v", value, err))
147 }
148 return pr
149}