@@ -40,38 +40,62 @@ func hostAddress(rule limayaml.PortForward, guest api.IPPort) string {
40
40
return host .String ()
41
41
}
42
42
43
- func tcpRuleIsWithinBounds (guest api.IPPort , rule limayaml.PortForward ) bool {
44
- if rule .GuestSocket != "" {
45
- // Not TCP
46
- return false
47
- }
43
+ func (pf * portForwarder ) forwardingAddresses (guest api.IPPort ) (hostAddr string , guestAddr string ) {
44
+ // Some rules will require a small patch to the HostIP in order to bind to the
45
+ // correct IP family.
46
+ mustAdjustHostIP := false
48
47
49
- // Check if `guest.Port` is within `rule.GuestPortRange`
50
- return guest .Port >= rule .GuestPortRange [0 ] && guest .Port <= rule .GuestPortRange [1 ]
51
- }
48
+ // This holds an optional rule that was rejected, but is now stored here to preserve backward
49
+ // compatibility, and will be used at the bottom of this function if set. See the case
50
+ // rule.GuestIPMustBeZero && guest.IP.IsUnspecified() for further info.
51
+ var unspecifiedRuleFallback * limayaml.PortForward
52
52
53
- func (pf * portForwarder ) forwardingAddresses (guest api.IPPort ) (hostAddr string , guestAddr string ) {
54
- // Check if it matches new IPv6 rule, otherwise fallback to the pre-IPv6 checks to maintain
55
- // compatibility
56
53
for _ , rule := range pf .rules {
57
- if ! tcpRuleIsWithinBounds (guest , rule ) {
54
+ if rule .GuestSocket != "" {
55
+ // Not TCP
58
56
continue
59
57
}
60
58
61
- // guest.IP and HostIP must be either :: or 0.0.0.0, and be forwarded to the same family on HostIP
62
- if guest .IP .IsUnspecified () && rule .HostIP .IsUnspecified () && ((guest .IP .To4 () == nil ) == (rule .HostIP .To4 () == nil )) {
63
- return hostAddress (rule , guest ), guest .String ()
64
- }
65
- }
66
-
67
- // Before giving up, try to match against the old rule set
68
- for _ , rule := range pf .rules {
69
- if ! tcpRuleIsWithinBounds (guest , rule ) {
59
+ // Check if `guest.Port` is within `rule.GuestPortRange`
60
+ if guest .Port < rule .GuestPortRange [0 ] || guest .Port > rule .GuestPortRange [1 ] {
70
61
continue
71
62
}
72
63
73
64
switch {
74
- case guest .IP .IsUnspecified ():
65
+ // Early-continue in case rule's IP is not zero while it is required.
66
+ case rule .GuestIPMustBeZero && ! guest .IP .IsUnspecified ():
67
+ continue
68
+
69
+ // Rule lacks a preferred GuestIP, so guest may be binding to wherever it wants. The rule matches the port range,
70
+ // so we can continue processing it. However, make sure to correct the rule to use a correct address family if
71
+ // not specified by the rule.
72
+ case rule .GuestIPWasUndefined && ! rule .GuestIPMustBeZero :
73
+ mustAdjustHostIP = rule .HostIPWasUndefined
74
+
75
+ // if GuestIP and family matches, move along.
76
+ case rule .GuestIPMustBeZero && guest .IP .IsUnspecified ():
77
+ // This is a breaking change. Here we will keep a backup of the rule, so we can still reuse it
78
+ // in case everything fails. The idea here is to move a copy of the current rule to outside this
79
+ // loop, so we can reuse it in case nothing else matches.
80
+ if ! rule .GuestIPWasUndefined && ! guest .IP .Equal (rule .GuestIP ) {
81
+ if unspecifiedRuleFallback == nil {
82
+ // Move the rule to obtain a copy
83
+ func (p limayaml.PortForward ) { unspecifiedRuleFallback = & p }(rule )
84
+ }
85
+ continue
86
+ }
87
+
88
+ mustAdjustHostIP = true
89
+
90
+ // Rule lack's HostIP, and guest is binding to '0.0.0.0' or '::'. Bind to the same address family.
91
+ case rule .HostIPWasUndefined && guest .IP .IsUnspecified ():
92
+ mustAdjustHostIP = true
93
+
94
+ // We don't have a preferred HostIP in the rule, and guest wants to bind to a loopback
95
+ // address. In that case, use the same address family.
96
+ case rule .HostIPWasUndefined && (guest .IP .Equal (net .IPv6loopback ) || guest .IP .Equal (api .IPv4loopback1 )):
97
+ mustAdjustHostIP = true
98
+
75
99
case guest .IP .Equal (rule .GuestIP ):
76
100
case guest .IP .Equal (net .IPv6loopback ) && rule .GuestIP .Equal (api .IPv4loopback1 ):
77
101
case rule .GuestIP .IsUnspecified () && ! rule .GuestIPMustBeZero :
@@ -80,15 +104,32 @@ func (pf *portForwarder) forwardingAddresses(guest api.IPPort) (hostAddr string,
80
104
default :
81
105
continue
82
106
}
107
+
83
108
if rule .Ignore {
84
109
if guest .IP .IsUnspecified () && ! rule .GuestIP .IsUnspecified () {
85
110
continue
86
111
}
112
+
87
113
break
88
114
}
115
+
116
+ if mustAdjustHostIP {
117
+ if guest .IP .To4 () != nil {
118
+ rule .HostIP = api .IPv4loopback1
119
+ } else {
120
+ rule .HostIP = net .IPv6loopback
121
+ }
122
+ }
123
+
89
124
return hostAddress (rule , guest ), guest .String ()
90
125
}
91
126
127
+ // At this point, no other rule matched. So check if this is being impacted by our
128
+ // breaking change, and return the fallback rule. Otherwise, just ignore it.
129
+ if unspecifiedRuleFallback != nil {
130
+ return hostAddress (* unspecifiedRuleFallback , guest ), guest .String ()
131
+ }
132
+
92
133
return "" , guest .String ()
93
134
}
94
135
0 commit comments