Skip to content
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: correctly compare compressed/expanded ipv6 in targets #109

Merged
merged 4 commits into from
Jul 4, 2024

Conversation

GGabriele
Copy link
Collaborator

When syncing a target with a compressed IPv6 (for example [2001:db8:fd73::e]:1326) decK can successfully create it but it fails to detect its existence when pulling the config from the API because the CP expands the address (for example to [2001:0db8:fd73:0000:0000:0000:0000:000e]:1326) causing decK to attempt to recreate the target and failing because the target already exists.

This commit fixes this by using some helpers to expand the ipv6 before trying to sync/dump.

Summary

SUMMARY_GOES_HERE

Full changelog

  • [Implement ...]
  • [Fix ...]

Issues resolved

Fix #XXX

Documentation

Testing

  • Unit tests
  • E2E tests
  • Manual testing on Universal
  • Manual testing on Kubernetes

@GGabriele GGabriele requested a review from a team July 1, 2024 11:44
@codecov-commenter
Copy link

codecov-commenter commented Jul 1, 2024

Codecov Report

Attention: Patch coverage is 87.23404% with 6 lines in your changes missing coverage. Please review.

Project coverage is 41.42%. Comparing base (c70e4ec) to head (6764fd2).

Files Patch % Lines
pkg/file/builder.go 87.23% 4 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #109      +/-   ##
==========================================
+ Coverage   41.23%   41.42%   +0.19%     
==========================================
  Files          75       75              
  Lines       10793    10840      +47     
==========================================
+ Hits         4450     4491      +41     
- Misses       5881     5885       +4     
- Partials      462      464       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Comment on lines +1046 to +1047
parts := strings.Split(hostname, ":")
return len(parts) > 2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be prone to errors or to be misused. Why not use https://pkg.go.dev/net/netip#ParseAddr and https://pkg.go.dev/net/netip#Addr.Is6 ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As silly as it may look, this is enough to catch all combinations of targets in IPv6 format, including the one with port and brackets like [2600:1f16:1784:fa03:fd73::e]:1326, which the library wouldn't consider as v6

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't https://pkg.go.dev/net/netip#ParseAddrPort work for this then?

I'm just worried that this func is very easy to abuse.

isIPv6("this:is:nuts:!") will also return true. It will also return true for 1:2:3:4 which http://sqa.fyicenter.com/1000334_IPv6_Address_Validator.html#Result reports as invalid.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ParseAddrPort works if the port is always there, but it would fail to parse things like ::1 (would work with [::1]:8000 though).

If you really feel strong about this we can improve this validation, but generally decK (or this library) doesn't do much input validation other than what's part of the JSON schemas from go-kong.

For the records though, those bogus entries would still fail validation at a later stage:

$ ./deck gateway sync kong.yaml
Error: building state: invalid ipv6 address 1:2:3:4

$ ./deck gateway sync kong.yaml
Error: building state: invalid ipv6 address this:is:nuts:!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood that this is validated on other levels.

I'm just suggesting to consider improving the reliability of this while we're at it

For instance something like this should work just fine and will work for addresses with and without ports

func IsIPv6(str string) bool {
	addr, err := netip.ParseAddrPort(str)
	if err != nil {
		addr, err := netip.ParseAddr(str)
		fmt.Printf("error parsing address: %v\n", err)
		if err != nil {
			fmt.Printf("error parsing address port: %v\n", err)
			return false
		}
		return addr.Is6()
	}

	return addr.Addr().Is6()
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still would fail to parse something like [::1], as well as detecting bogus patterns like [invalid:ipv6::address]:1326: the function would rightly return false, but this is not just false, it's invalid. At this point we would need add extra handling and validation for these cases too. I think this is going to become more complex and fragile overall.

I'm renaming this function to hasIPv6Format which better represent its purpose: 6764fd2

pkg/file/builder.go Show resolved Hide resolved
pkg/file/builder.go Show resolved Hide resolved
When syncing a target with a compressed IPv6 (for example
`[2001:db8:fd73::e]:1326`) decK can successfully create it
but it fails to detect its existence when pulling the config
from the API because the CP expands the address (for example to
`[2001:0db8:fd73:0000:0000:0000:0000:000e]:1326`) causing
decK to attempt to recreate the target and failing because the
target already exists.

This commit fixes this by using some helpers to expand the
ipv6 before trying to sync/dump.
@GGabriele GGabriele requested a review from pmalek July 3, 2024 16:04
pkg/file/builder.go Outdated Show resolved Hide resolved
// normalizeIPv6 normalizes an ipv6 address to the format [address]:port.
// for example:
// from ::1 to [0000:0000:0000:0000:0000:0000:0000:0001]:8000.
func normalizeIPv6(target string) (string, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't we also use StringExpanded() here? Possibly with a port?

Comment on lines +1046 to +1047
parts := strings.Split(hostname, ":")
return len(parts) > 2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't https://pkg.go.dev/net/netip#ParseAddrPort work for this then?

I'm just worried that this func is very easy to abuse.

isIPv6("this:is:nuts:!") will also return true. It will also return true for 1:2:3:4 which http://sqa.fyicenter.com/1000334_IPv6_Address_Validator.html#Result reports as invalid.

pmalek
pmalek previously approved these changes Jul 3, 2024
Copy link
Member

@pmalek pmalek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks good and serves it's purpose 👍

Feel free to address the comments or merge as is if time is of the essence.

@GGabriele GGabriele merged commit 7c387d4 into main Jul 4, 2024
42 checks passed
@GGabriele GGabriele deleted the fix/target-ipv6 branch July 4, 2024 07:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants