AlinsRan opened a new pull request, #13911:
URL: https://github.com/apache/apisix/pull/13911
### Description
### Why
Gateway API `TLSRoute.hostnames` is a **list** of SNI names, but the stream
router can only
express one SNI per route: `stream_route.sni` is a single string and
`apisix/stream/router/ip_port.lua` does `route.sni:reverse()`. An ingress
controller therefore has
to fan a multi-hostname `TLSRoute` out into N `stream_routes`, which
duplicates the plugins and the
traffic-split state once per SNI.
`service.hosts` already exists and uses the same `host_def_pat` as
`stream_route.sni`, so it can
already hold exactly the values `sni` can, wildcards included. It was simply
never consulted by the
stream router.
### What
`create_router()` now registers one radixtree path per SNI instead of one
per route, and takes the
SNI list from:
1. `stream_route.sni`, when it is set;
2. otherwise the `hosts` of the service the route references.
This mirrors the host precedence the HTTP router already implements in
`apisix/http/router/radixtree_host_uri.lua`.
Two details worth calling out:
* A bare `*` host means "no SNI restriction": the route stays in the
address-matched set, exactly
as a route without `sni` does today. Reversed into the radixtree it would
only ever match a
literal `*`.
* The service hosts are lowercased when the router is built, because
`apisix/ssl.lua`'s
`server_name()` returns a lowercased SNI — `apisix/router.lua` already
does the same for the
`hosts` of an HTTP route.
### Backward compatibility
**This is a behavior change.** Today a `stream_route` that has no `sni` and
whose `service_id`
points at a service that has `hosts` matches *every* SNI on the port;
afterwards it matches only
those hosts. Sharing one service between HTTP routes and stream routes is
unusual but possible, so
such a deployment will see stream connections whose SNI is outside the
service's `hosts` stop
matching that route.
### Tests
`t/stream-node/service-hosts.t` covers:
* a multi-host service matched on each of its hosts, and not matched on a
host it does not carry;
* `stream_route.sni` taking precedence over the hosts of the service;
* a wildcard host (`*.test.com`);
* a bare `*` host falling through to the address-matched routes;
* a mixed-case host (`Mixed.TEST.com`) matched by a lowercase SNI.
The TLS requests are issued from inside the same nginx instance that
performs the setup, so the
SNI router is only exercised once the stream subsystem has synced the
configuration from etcd —
unlike `--- stream_tls_request`, which restarts nginx and then races the
etcd sync in
`ssl_client_hello_by_lua`.
### Related
The same change is applied to the API7 enterprise gateway in
api7/api7-ee-3-gateway#2199 (private
repository); the two `apisix/stream/router/ip_port.lua` files are kept
identical for this feature.
### Checklist
- [x] I have explained the need for this PR and the problem it solves
- [x] I have explained the changes or the new features added to this PR
- [x] I have added tests corresponding to this change
- [x] I have updated the documentation to reflect this change
- [ ] I have verified that this change is backward compatible — see the
"Backward compatibility"
section above; a stream route with no `sni` whose service carries
`hosts` becomes restricted
to those hosts.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]