-
Notifications
You must be signed in to change notification settings - Fork 188
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix the bug that GetIndexedIP does not support IPv6 #145
Conversation
a56b0f3
to
b4f679b
Compare
wow, great catch, is just not the leading zero, it depends on the bigInt representation, per example |
net/net.go
Outdated
} | ||
ipBytes := big.NewInt(0).Add(base, big.NewInt(int64(offset))).Bytes() | ||
ipBytesLength := len(ipBytes) | ||
if ipBytesLength > length { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this case possible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can try extreme scenario like this:
ip := net.ParseIP("255.255.255.0")
res := AddNetIPOffset(ip, 256)
Without this line, the underlying byte slice of res
will be [1,0,0,0,0]
. Not a valid IP.
actually the ip address returned by
using
https://golang.org/src/net/ip.go?s=315:321#L319
|
net/net.go
Outdated
@@ -161,8 +161,21 @@ func BigForIP(ip net.IP) *big.Int { | |||
|
|||
// AddIPOffset adds the provided integer offset to a base big.Int representing a | |||
// net.IP | |||
func AddIPOffset(base *big.Int, offset int) net.IP { | |||
return net.IP(big.NewInt(0).Add(base, big.NewInt(int64(offset))).Bytes()) | |||
func AddIPOffset(base *big.Int, offset int, isIPv6 bool) net.IP { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you know if modifying BigForIP
to return the bigInt with correct length would solve the issue?
the benefit is that BigFortIP "knows" the right length and this way we don't have to modify this function passing an additional parameter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't change existing method signatures. If needed, deprecate this one and delegate to a second method that takes an ipv6 param
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
modifying BigForIP()
is useless, because bigInt
s are normalized after arithmetics operations, however, we can add a new function that receives an IP as a parameter instead of the bigInt,
I've tested this and it works
// AddNetIPOffset adds the provided integer offset to an IP address
func AddNetIPOffset(ip net.IP, offset int) net.IP {
length := len(ip)
base := new(big.Int).SetBytes(ip)
ipBytes := big.NewInt(0).Add(base, big.NewInt(int64(offset))).Bytes()
ipBytesLength := len(ipBytes)
if ipBytesLength < length {
b := make([]byte, length-ipBytesLength, length)
return net.IP(append(b, ipBytes...))
}
return net.IP(ipBytes)
}
https://golang.org/src/math/big/nat.go
:/ |
b4f679b
to
e463149
Compare
cidr: "00:00:00:be::/120", | ||
index: 255, | ||
expectError: false, | ||
expectedIP: "::be:0:0:0:ff", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fmt.Println(net.ParseIP("00:00:00:be::ff"))
::be:0:0:0:ff
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is a "tomato, tomato" thing, my understanding is that you can choose where you want to use the ::
, it may be at the beginning or at the end of the address, the only restriction is that only can be used once
- Due to some methods of allocating certain styles of IPv6
addresses, it will be common for addresses to contain long strings
of zero bits. In order to make writing addresses containing zero
bits easier, a special syntax is available to compress the zeros.
The use of "::" indicates one or more groups of 16 bits of zeros.
The "::" can only appear once in an address. The "::" can also be
used to compress leading or trailing zeros in an address.
ref: https://tools.ietf.org/html/rfc4291#page-4
However, the recommendation is, if the blocks of zeroes have the same length, using it for the first sequence of zeroes:
4.2.3. Choice in Placement of "::"
When there is an alternative choice in the placement of a "::", the
longest run of consecutive 16-bit 0 fields MUST be shortened (i.e.,
the sequence with three consecutive zero fields is shortened in 2001:
0:0:1:0:0:0:1). When the length of the consecutive 16-bit 0 fields
are equal (i.e., 2001:db8:0:0:1:0:0:1), the first sequence of zero
bits MUST be shortened. For example, 2001:db8::1:0:0:1 is correct
representation.
/lgtm
but
|
kindly ping @thockin ! |
Hi @liggitt |
My comment was only around the mechanics of the k8s.io/utils compatibility. I think someone from sig-network is a better review for the actual change being made. |
This PR both fixes the bug and changes the API. Whether you like the API or not, I don't see why it needs to change (or rather, that is orthogonal to the bug) Why can't we just treat everything at v6, and pad the slice to 16 bytes? Look at this playground - what test cases would show where this is wrong? https://play.golang.org/p/IVioicnTFY3 The only really odd thing here is that overflowing a v4 address 255.255.255.255 + 1 just converts into a v6 result. Fixing that would require an API change, which I would be fine to consider in a different PR. The code, in case playground fails:
|
That seems like it should work. I don't think the function is really expected to be well-defined in the case where you overflow the IP address. |
/kind bug |
@SataQiu Will you have time to adapt this? Otherwise I can take a shot. We'll need to re-vendor it. |
Thanks for your guidance @thockin ! |
e463149
to
605144a
Compare
/lgtm |
/hold cancel |
Thank you everyone for working on this. |
Thanks! /lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: aojea, SataQiu, thockin The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
This fixes a bug where GetIndexedIP would fail to produce correct IPv6 addresses if the IPv6 address contains leading zeros. This bug has been fixed in upstream for a while: kubernetes/utils#145 Signed-off-by: Sebastian Wicki <sebastian@isovalent.com>
This fixes a bug where GetIndexedIP would fail to produce correct IPv6 addresses if the IPv6 address contains leading zeros. This bug has been fixed in upstream for a while: kubernetes/utils#145 Signed-off-by: Sebastian Wicki <sebastian@isovalent.com>
Signed-off-by: SataQiu 1527062125@qq.com
Ref: kubernetes/kubernetes#88933
The reason is that the returned byte slice of
big.NewInt(0).Add(base, big.NewInt(int64(offset))).Bytes()
does not include the leading zero byte.We need to check and correct the length of the byte slice before converting it to IP.