grpc-go
                                
                                 grpc-go copied to clipboard
                                
                                    grpc-go copied to clipboard
                            
                            
                            
                        dns: scoped literal IPv6 addresses should be supported
fe80::1ff:fe23:4567:890a%eth2 is a valid IPv6 address, and should be supported in the DNS resolver
net.Dial("dns:///fe80::1ff:fe23:4567:890a%eth2:8080")
It fails with ParseIP error now.
https://en.wikipedia.org/wiki/IPv6_address#Scoped_literal_IPv6_addresses
Literal IPv6 addresses with zone identifer are supported by functions like net.Dial (https://github.com/golang/go/commit/aa0dda767a9a31c6b0b49a665f0d059ebfed8e1c), but not net.ParseIP. The default DNS resolver also supports this address.
A work-around now is to use passthrough as the resolver.
To solve this in the DNS resolver, we can remove the special code for IPs (so we don't call ParseIP), and let the default go DNS resolver handle everything.
use [fdbd:dc02:ff:1:1:225:111:82]:9238 format will resolve
The issue is interesting, I'm willing to take this task up.
@menghanl  After I read code and your instruction, I think the solution is to remove net.ParseIP in formatIP but remain net.ParseIP in parseTarget. Is this right?
https://github.com/grpc/grpc-go/blob/a42567fe92f005c47e60146bdbb0d5f7fc232219/internal/resolver/dns/dns_resolver.go#L364
https://github.com/grpc/grpc-go/blob/a42567fe92f005c47e60146bdbb0d5f7fc232219/internal/resolver/dns/dns_resolver.go#L387
It's not enough to remove net.ParseIP, because address will be not verified.
We could still use ParseIP for verifying if it is in high version.
parseIPv6 support literal IPv6
OMG,the solution above is wrong.
The solution is removing the IP resolver , and let the default go DNS resolver handle everything.
However, customAuthorityResolver call formatIP and parseTarget.
There is still some wrong.
I don't remember all the details about this issue.
But I think if we want to keep our handling of IPs, we can update formatIP and parseTarget to handle scopes.
Seems it's as easy as finding the %: https://cs.opensource.google/go/go/+/refs/tags/go1.17:src/net/ip.go;l=592
If the DNS resolver can recognize this address, it can just return it as is, and net.Dial will handle it correctly.
Note that in ParseIP (and when used with gRPC), the address should be put in brackets dns:///[fe80::1ff:fe23:4567:890a%eth2]:8080
Yes, I notice that dns:///[fe80::1ff:fe23:4567:890a%eth2]:8080 is supported instead of net.Dial("dns:///fe80::1ff:fe23:4567:890a%eth2:8080") 
Is there any solution for grpc.Dial to connect to ipv6 with scope? Maybe example? Now with passthrough returns error invalid URL escape
Works for me:
tcp:[fe80::1ff:fe23:4567:890a%25eth2]:8080
url.Parse issue: https://github.com/golang/go/issues/30611
In a URI, a literal IPv6 address is always embedded between "[" and
   "]".  This document specifies how a <zone_id> can be appended to the
   address.  According to URI syntax [[RFC3986](https://www.rfc-editor.org/rfc/rfc3986)], "%" is always treated as
   an escape character in a URI, so, according to the established URI
   syntax [[RFC3986](https://www.rfc-editor.org/rfc/rfc3986)] any occurrences of literal "%" symbols in a URI MUST
   be percent-encoded and represented in the form "%25".  Thus, the
   scoped address fe80::a%en1 would appear in a URI as
   http://[fe80::a%25en1].
Given that the net package now supports parsing of IPv6 scoped literals, all we need to do is to ensure that this actually works for us, and to have a test for the same. Before that (or as part of that) though, we need to cleanup dns_resolver_test.go, which is currently a mess.