2c32ec0f3a
A *.example.com wildcard host now chooses between two routing modes: - wildcard_matchAny=false (default): only subdomains explicitly defined in redis route; undefined subdomains get no match (406) - wildcard_matchAny=true: any subdomain catches-all to the wildcard parent host, preserving the previous behavior The gate lives in the host_lookup socket service, which is only reached for domains missing a direct redis entry, so defined children and **-style hosts are unaffected. Adds the matching-mode selector to the host add/edit form, shown for wildcard hosts. Note: existing wildcard hosts have no wildcard_matchAny field and so default to the stricter "only defined" mode until re-saved. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
73 lines
2.6 KiB
JavaScript
73 lines
2.6 KiB
JavaScript
'use strict';
|
|
|
|
const {Host} = require('../models/host');
|
|
const {SocketServerJson} = require('../utils/unix_socket_json');
|
|
const conf = require('@simpleworkjs/conf');
|
|
|
|
/**
|
|
* Host Lookup Service
|
|
*
|
|
* Unix socket server that handles host/domain lookup requests from OpenResty.
|
|
* This provides the bridge between nginx (Lua) and the Node.js host management system.
|
|
*
|
|
* Flow:
|
|
* 1. OpenResty sends domain lookup request via Unix socket
|
|
* 2. Service queries Host model (supports wildcards via lookup tree)
|
|
* 3. Returns host configuration (IP, port, SSL settings, etc.)
|
|
* 4. All values converted to strings for Redis compatibility
|
|
*
|
|
* Redis Compatibility:
|
|
* All object values are converted to strings before sending because:
|
|
* - Redis stores everything as strings
|
|
* - OpenResty's primary lookup path uses Redis directly (hgetall)
|
|
* - This socket is a fallback when Redis cache misses
|
|
* - Both paths must return identical data structures to Lua consumer
|
|
*/
|
|
|
|
const socket = new SocketServerJson({
|
|
socketFile: conf.socketFile,
|
|
|
|
onData: function(data, clientSocket) {
|
|
try{
|
|
// Try to match the requested host name using the lookup tree
|
|
let parentHost = Host.lookUp(data['domain']);
|
|
|
|
// If we don't have a match, return empty object
|
|
if(!parentHost) return clientSocket.write(JSON.stringify({}));
|
|
|
|
// A wildcard host with matchAny disabled only serves subdomains that
|
|
// are explicitly defined in redis. Reaching this service means redis
|
|
// had no direct entry for the requested domain, so an inexact match
|
|
// here (the request isn't the wildcard host itself) is an undefined
|
|
// subdomain and must not be routed to the wildcard parent.
|
|
if(parentHost.is_wildcard && !parentHost.wildcard_matchAny
|
|
&& parentHost.host !== data['domain']){
|
|
return clientSocket.write(JSON.stringify({}));
|
|
}
|
|
|
|
// If the matched host belongs to a wildcard domain, set wildcard_parent
|
|
// This allows child domains to use the parent's wildcard SSL certificate
|
|
if(!parentHost.wildcard_parent){
|
|
parentHost.wildcard_parent = parentHost.host;
|
|
Host.addCache(data['domain'], parentHost);
|
|
}
|
|
|
|
// Convert all values to strings for Redis compatibility
|
|
// OpenResty expects the same data format from both Redis and this socket
|
|
for(const [key, value] of Object.entries(parentHost)) {
|
|
parentHost[key] = String(value);
|
|
}
|
|
|
|
clientSocket.write(JSON.stringify(parentHost));
|
|
}catch(error){
|
|
console.error('services/host_lookup onData error', error);
|
|
}
|
|
},
|
|
|
|
onListen: function(){
|
|
console.log('Host lookup service listening on', conf.socketFile);
|
|
}
|
|
});
|
|
|
|
module.exports = {socket};
|