GH-3798: Add near=_ip support for prepared queries
This commit is contained in:
parent
d5b8b75614
commit
89cd24aeca
|
@ -393,6 +393,23 @@ func (p *PreparedQuery) Execute(args *structs.PreparedQueryExecuteRequest,
|
|||
// Respect the magic "_agent" flag.
|
||||
if qs.Node == "_agent" {
|
||||
qs.Node = args.Agent.Node
|
||||
} else if qs.Node == "_ip" {
|
||||
if args.Source.Ip != "" {
|
||||
_, nodes, err := state.Nodes(nil)
|
||||
if err == nil {
|
||||
for _, node := range nodes {
|
||||
if args.Source.Ip == node.Address {
|
||||
qs.Node = node.Node
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Either a source IP was given but we couldnt find the associated node
|
||||
// or no source ip was given. In both cases we should wipe the Node value
|
||||
if qs.Node == "_ip" {
|
||||
qs.Node = ""
|
||||
}
|
||||
}
|
||||
|
||||
// Perform the distance sort
|
||||
|
|
23
agent/dns.go
23
agent/dns.go
|
@ -917,6 +917,23 @@ func (d *DNSServer) serviceLookup(network, datacenter, service, tag string, req,
|
|||
}
|
||||
}
|
||||
|
||||
func ednsSubnetForRequest(req *dns.Msg) (*dns.EDNS0_SUBNET) {
|
||||
// Its probably not obvious but IsEdns0 returns the EDNS RR if present or nil otherwise
|
||||
edns := req.IsEdns0()
|
||||
|
||||
if edns == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, o := range edns.Option {
|
||||
if subnet, ok := o.(*dns.EDNS0_SUBNET); ok {
|
||||
return subnet
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
// preparedQueryLookup is used to handle a prepared query.
|
||||
func (d *DNSServer) preparedQueryLookup(network, datacenter, query string, req, resp *dns.Msg) {
|
||||
// Execute the prepared query.
|
||||
|
@ -938,6 +955,12 @@ func (d *DNSServer) preparedQueryLookup(network, datacenter, query string, req,
|
|||
Node: d.agent.config.NodeName,
|
||||
},
|
||||
}
|
||||
|
||||
subnet := ednsSubnetForRequest(req)
|
||||
|
||||
if subnet != nil {
|
||||
args.Source.Ip = subnet.Address.String()
|
||||
}
|
||||
|
||||
// TODO (slackpad) - What's a safe limit we can set here? It seems like
|
||||
// with dup filtering done at this level we need to get everything to
|
||||
|
|
|
@ -498,11 +498,33 @@ func (s *HTTPServer) parseToken(req *http.Request, token *string) {
|
|||
*token = s.agent.tokens.UserToken()
|
||||
}
|
||||
|
||||
func sourceAddrFromRequest(req *http.Request) (string, error) {
|
||||
host, _, err := net.SplitHostPort(req.RemoteAddr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
ip := net.ParseIP(host)
|
||||
if ip == nil {
|
||||
return "", fmt.Errorf("Could not get IP from request")
|
||||
}
|
||||
|
||||
forwardHost := req.Header.Get("X-Forwarded-For")
|
||||
forwardIp := net.ParseIP(forwardHost)
|
||||
if forwardIp != nil {
|
||||
return forwardIp.String(), nil
|
||||
} else {
|
||||
return ip.String(), nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// parseSource is used to parse the ?near=<node> query parameter, used for
|
||||
// sorting by RTT based on a source node. We set the source's DC to the target
|
||||
// DC in the request, if given, or else the agent's DC.
|
||||
func (s *HTTPServer) parseSource(req *http.Request, source *structs.QuerySource) {
|
||||
s.parseDC(req, &source.Datacenter)
|
||||
source.Ip, _ = sourceAddrFromRequest(req)
|
||||
if node := req.URL.Query().Get("near"); node != "" {
|
||||
if node == "_agent" {
|
||||
source.Node = s.agent.config.NodeName
|
||||
|
|
|
@ -258,6 +258,7 @@ type QuerySource struct {
|
|||
Datacenter string
|
||||
Segment string
|
||||
Node string
|
||||
Ip string
|
||||
}
|
||||
|
||||
// DCSpecificRequest is used to query about a specific DC
|
||||
|
|
Loading…
Reference in New Issue