Skip to content

Commit fa11f6c

Browse files
committed
dnssec-monitor: use verification port to enable tls
1 parent f7754ad commit fa11f6c

8 files changed

Lines changed: 295 additions & 44 deletions

File tree

lib/system/async-dns/async-dns.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,7 @@ lws_async_dns_init(struct lws_context *context)
725725
}
726726

727727
n = lws_plat_asyncdns_init(context, dns);
728-
if (n < 0 && !dns->nameservers.count) {
728+
if (!dns->nameservers.count) {
729729
lwsl_cx_warn(context, "no valid dns server, retry");
730730

731731
return 1;

lib/system/auth-dns/auth-dns.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,7 @@ lws_auth_dns_sign_zone(struct lws_auth_dns_sign_info *info)
331331
{
332332
char obuf[8192]; /* simple large enough buffer for test */
333333
int fd, n, ofd = -1, res_wr, temp_len = 0, temp_max = 0;
334-
size_t uin = 0, uout = 0;
335-
lws_strexp_t exp;
334+
size_t uout = 0;
336335
struct stat st;
337336
char *buf, *expbuf;
338337
ssize_t ns;

lib/system/system.c

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -269,19 +269,26 @@ lws_extip_report(struct lws_context *cx, lws_extip_src_t src,
269269
const lws_sockaddr46 *sa46, int af, int status,
270270
const lws_sockaddr46 *peers, int num_peers)
271271
{
272-
lws_sockaddr46 *target = (af == AF_INET) ? &cx->ext_ipv4 : &cx->ext_ipv6;
272+
lws_sockaddr46 *target = &cx->ext_ipv4;
273+
#if defined(LWS_WITH_IPV6)
274+
if (af == AF_INET6)
275+
target = &cx->ext_ipv6;
276+
#endif
273277
lws_sockaddr46 old = *target;
274278

275-
if (status == 2 || !sa46 || (af == AF_INET && sa46->sa4.sin_family == 0) ||
276-
(af == AF_INET6 && sa46->sa6.sin6_family == 0)) {
279+
if (status == 2 || !sa46 || (af == AF_INET && sa46->sa4.sin_family == 0)
280+
#if defined(LWS_WITH_IPV6)
281+
|| (af == AF_INET6 && sa46->sa6.sin6_family == 0)
282+
#endif
283+
) {
277284
memset(target, 0, sizeof(*target));
278285
} else {
279286
*target = *sa46;
280287
}
281288

282289
if (memcmp(&old, target, sizeof(*target))) {
283290
int c = 0;
284-
char payload[128], buf4[64], buf6[64];
291+
char payload[128], buf4[64];
285292
char *p = payload, *end = payload + sizeof(payload);
286293

287294
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "{\"ext-ips\": [");
@@ -292,12 +299,15 @@ lws_extip_report(struct lws_context *cx, lws_extip_src_t src,
292299
c++;
293300
}
294301

302+
#if defined(LWS_WITH_IPV6)
295303
if (cx->ext_ipv6.sa6.sin6_family == AF_INET6) {
304+
char buf6[64];
296305
lws_sa46_write_numeric_address(&cx->ext_ipv6, buf6, sizeof(buf6));
297306
if (c)
298307
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ", ");
299308
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"%s\"", buf6);
300309
}
310+
#endif
301311

302312
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "]}");
303313

@@ -308,10 +318,18 @@ lws_extip_report(struct lws_context *cx, lws_extip_src_t src,
308318
int
309319
lws_extip_get_best(struct lws_context *cx, int af, lws_sockaddr46 *sa46)
310320
{
311-
lws_sockaddr46 *src = (af == AF_INET) ? &cx->ext_ipv4 : &cx->ext_ipv6;
321+
lws_sockaddr46 *src = &cx->ext_ipv4;
312322

313-
if ((af == AF_INET && src->sa4.sin_family == AF_INET) ||
314-
(af == AF_INET6 && src->sa6.sin6_family == AF_INET6)) {
323+
#if defined(LWS_WITH_IPV6)
324+
if (af == AF_INET6)
325+
src = &cx->ext_ipv6;
326+
#endif
327+
328+
if ((af == AF_INET && src->sa4.sin_family == AF_INET)
329+
#if defined(LWS_WITH_IPV6)
330+
|| (af == AF_INET6 && src->sa6.sin6_family == AF_INET6)
331+
#endif
332+
) {
315333
if (sa46)
316334
*sa46 = *src;
317335
return 0; /* found */

plugins/protocol_lws_dht_dnssec/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,20 @@ The following substitution keys are provided:
6666
- `${DANE0}`: Generates a DANE TLSA SHA-256 signature string for the *current* active TLS certificate. The parser natively identities the target `<domain>` context from the front of the corresponding record line (such as `_443._tcp.warmcat.com. IN TLSA ...`) and accesses `/var/dnssec/domains/<domain>/tls/<domain>.crt` to actively compute the `3 1 1 <hash>` DANE data.
6767
- `${DANE1}`: Acts identically to `DANE0`, however signs the *previous* archived certificate by checking `/var/dnssec/domains/<domain>/tls/<domain>.crt.1`.
6868

69+
### Substitution Examples
70+
If an operator authors the following raw zone file config:
71+
```text
72+
example.com. IN A ${EXTIP4}
73+
example.com. IN AAAA ${EXTIP6}
74+
_443._tcp.example.com. IN TLSA ${DANE0}
75+
_443._tcp.example.com. IN TLSA ${DANE1}
76+
```
77+
78+
Upon `signzone`:
79+
- If the node **lacks an external IPv6 address**, the entire `example.com. IN AAAA ${EXTIP6}` line will be seamlessly excluded from the resulting signed zone.
80+
- The `${DANE0}` key evaluates `_443._tcp.example.com.` and automatically locates `/var/dnssec/domains/example.com/tls/example.com.crt`. It hashes the embedded SPKI, returning `3 1 1 e3b0c4429...`.
81+
- If no archived certificate (`example.com.crt.1`) exists, the second TLSA line containing `${DANE1}` will drop itself natively.
82+
6983
## `lws-crypto-dnssec` Utility
7084
Libwebsockets provides the `<build-dir>/bin/lws-crypto-dnssec` standalone utility that interfaces dynamically using the `lws-dht-dnssec` plugin.
7185

plugins/protocol_lws_dht_dnssec/protocol_lws_dht_dnssec.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3821,28 +3821,30 @@ dnssec_subst_cb(struct lws_auth_dns_sign_info *info, const char *name)
38213821
free(pembuf);
38223822

38233823
/* extracted SPKI */
3824-
union lws_tls_cert_info_results res;
3825-
res.ns.name = NULL;
3826-
res.ns.len = 0;
3827-
3828-
if (lws_x509_info(cert, LWS_TLS_CERT_INFO_DER_SPKI, &res, 0) == -1 && res.ns.len > 0) {
3829-
res.ns.name = malloc((size_t)res.ns.len);
3830-
if (res.ns.name) {
3831-
if (lws_x509_info(cert, LWS_TLS_CERT_INFO_DER_SPKI, &res, res.ns.len) == 0) {
3824+
union lws_tls_cert_info_results res1;
3825+
union lws_tls_cert_info_results *res;
3826+
res1.ns.len = 0;
3827+
3828+
if (lws_x509_info(cert, LWS_TLS_CERT_INFO_DER_SPKI, &res1, 0) == -1 && res1.ns.len > 0) {
3829+
size_t alloc_len = sizeof(*res) - sizeof(res1.ns.name) + (size_t)res1.ns.len;
3830+
res = malloc(alloc_len);
3831+
if (res) {
3832+
res->ns.len = 0;
3833+
if (lws_x509_info(cert, LWS_TLS_CERT_INFO_DER_SPKI, res, (size_t)res1.ns.len) == 0) {
38323834
/* we have the DER SPKI, now hash it */
38333835
struct lws_genhash_ctx hash_ctx;
38343836
uint8_t hash[32];
38353837

38363838
if (!lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256)) {
3837-
if (!lws_genhash_update(&hash_ctx, res.ns.name, (size_t)res.ns.len)) {
3839+
if (!lws_genhash_update(&hash_ctx, (uint8_t *)res->ns.name, (size_t)res->ns.len)) {
38383840
if (!lws_genhash_destroy(&hash_ctx, hash)) {
38393841
char hex[128];
38403842
int hl = 0;
38413843
for (int i = 0; i < 32; i++) {
38423844
hl += lws_snprintf(hex + hl, sizeof(hex) - (size_t)hl, "%02X", hash[i]);
38433845
}
38443846
lws_snprintf(ret, sizeof(ret), "3 1 1 %s", hex);
3845-
free(res.ns.name);
3847+
free(res);
38463848
lws_x509_destroy(&cert);
38473849
return ret;
38483850
}
@@ -3851,7 +3853,7 @@ dnssec_subst_cb(struct lws_auth_dns_sign_info *info, const char *name)
38513853
}
38523854
}
38533855
}
3854-
free(res.ns.name);
3856+
free(res);
38553857
}
38563858
}
38573859

plugins/protocol_lws_dht_dnssec_monitor/assets/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ <h2 id="detail-title">Zone Records: <span>---</span></h2>
7070
<th>TTL</th>
7171
<th>Type</th>
7272
<th>Value</th>
73-
<th>TLS</th>
73+
<th>TLS Port</th>
7474
<th>Actions</th>
7575
</tr>
7676
</thead>
@@ -140,6 +140,6 @@ <h3>Add TLS Subdomain for <span id="tls-domain-name"></span></h3>
140140
<!-- Notification Toast -->
141141
<div id="toast" class="toast"></div>
142142

143-
<script src="monitor.js"></script>
143+
<script src="monitor.js?v=2"></script>
144144
</body>
145145
</html>

plugins/protocol_lws_dht_dnssec_monitor/assets/monitor.js

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
let ws;
22
let currentDomain = '';
33
let currentZone = null;
4+
let certCheckQueue = [];
5+
let isCheckingCert = false;
6+
7+
function processCertQueue() {
8+
if (isCheckingCert || certCheckQueue.length === 0) return;
9+
isCheckingCert = true;
10+
let task = certCheckQueue.shift();
11+
let span = document.getElementById(`cert-status-${task.fqdn}`);
12+
if (span) span.innerText = 'Checking...';
13+
sendReq({ req: 'check_cert', domain: currentDomain, subdomain: task.fqdn, port: task.port });
14+
}
415

516
function generateId() {
617
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
@@ -297,7 +308,21 @@ function handleResponse(data) {
297308
case 'create_tls':
298309
case 'delete_tls':
299310
showToast(data.req === 'create_tls' ? 'TLS collection enabled' : 'TLS collection disabled');
300-
sendReq({ req: 'get_tls', domain: currentDomain });
311+
// We don't fetch get_tls again because we update window.activeTls synchronously.
312+
break;
313+
case 'cert_status':
314+
let span = document.getElementById(`cert-status-${data.subdomain}`);
315+
if (span) {
316+
if (data.status === 'ok') {
317+
span.innerText = data.msg;
318+
span.style.color = '#34d399';
319+
} else {
320+
span.innerText = data.msg;
321+
span.style.color = '#f87171';
322+
}
323+
}
324+
isCheckingCert = false;
325+
processCertQueue();
301326
break;
302327
}
303328
}
@@ -375,6 +400,8 @@ function renderZoneTable() {
375400

376401
if (!currentZone) return;
377402

403+
certCheckQueue = [];
404+
isCheckingCert = false;
378405
window.renderedTlsFqdns = new Set();
379406
const records = currentZone.records.filter(r => r.type !== 'comment' && r.type !== 'macro');
380407

@@ -408,9 +435,13 @@ function renderZoneTable() {
408435

409436
if (isTlsCapable && !window.renderedTlsFqdns.has(fqdn)) {
410437
window.renderedTlsFqdns.add(fqdn);
411-
let checked = (window.activeTls && window.activeTls.includes(fqdn + '.json')) ? 'checked' : '';
438+
let activeConfig = window.activeTls ? window.activeTls.find(t => t.fqdn === fqdn) : null;
439+
let portVal = activeConfig ? activeConfig.port : '';
412440
tlsTd = `<td class="ext-tls-cell">
413-
<input type="checkbox" class="tls-checkbox" data-fqdn="${fqdn}" title="${fqdn}" ${checked}>
441+
<div style="display:flex; align-items:center; justify-content:flex-start; gap: 0.5rem">
442+
<input type="number" class="tls-port ext-port" data-fqdn="${fqdn}" value="${portVal}" maxlength="5" placeholder="Port" style="width:70px; background: rgba(0,0,0,0.2); color:#fff; border:1px solid #444; border-radius:4px; padding:2px;">
443+
<span id="cert-status-${fqdn}" class="cert-status" style="font-size:0.8em; color:#aaa;"></span>
444+
</div>
414445
</td>`;
415446
}
416447

@@ -422,19 +453,32 @@ function renderZoneTable() {
422453
${tlsTd}
423454
`;
424455

425-
const checkbox = tr.querySelector('.tls-checkbox');
426-
if (checkbox) {
427-
checkbox.onclick = (e) => e.stopPropagation();
428-
checkbox.onchange = (e) => {
429-
let isEnabled = e.target.checked;
430-
sendReq({ req: isEnabled ? 'create_tls' : 'delete_tls', domain: currentDomain, subdomain: fqdn });
431-
if (isEnabled) {
432-
if (!window.activeTls) window.activeTls = [];
433-
window.activeTls.push(fqdn + '.json');
456+
const portInput = tr.querySelector('.tls-port');
457+
if (portInput) {
458+
portInput.onclick = (e) => e.stopPropagation();
459+
portInput.onchange = (e) => {
460+
let p = e.target.value.trim();
461+
let pnum = parseInt(p, 10);
462+
if (!p || isNaN(pnum) || pnum <= 0 || pnum > 65535) {
463+
sendReq({ req: 'delete_tls', domain: currentDomain, subdomain: fqdn });
464+
if (window.activeTls) window.activeTls = window.activeTls.filter(x => x.fqdn !== fqdn);
465+
document.getElementById(`cert-status-${fqdn}`).innerText = '';
434466
} else {
435-
if (window.activeTls) window.activeTls = window.activeTls.filter(x => x !== fqdn + '.json');
467+
sendReq({ req: 'create_tls', domain: currentDomain, subdomain: fqdn, port: pnum });
468+
if (!window.activeTls) window.activeTls = [];
469+
let exist = window.activeTls.find(x => x.fqdn === fqdn);
470+
if (exist) exist.port = pnum;
471+
else window.activeTls.push({fqdn: fqdn, port: pnum});
472+
473+
certCheckQueue.push({fqdn: fqdn, port: pnum});
474+
processCertQueue();
436475
}
437476
};
477+
478+
if (portInput.value) {
479+
let pnum = parseInt(portInput.value, 10);
480+
certCheckQueue.push({fqdn: fqdn, port: pnum});
481+
}
438482
}
439483

440484
const tdAct = document.createElement('td');
@@ -622,8 +666,8 @@ function openEditor(id) {
622666
});
623667

624668
if (window.activeTls) {
625-
window.activeTls.forEach(tlsFilename => {
626-
let fqdn = tlsFilename.replace('.json', '');
669+
window.activeTls.forEach(obj => {
670+
let fqdn = obj.fqdn;
627671
if (!existingFqdns.has(fqdn)) {
628672
sendReq({ req: 'delete_tls', domain: currentDomain, subdomain: fqdn });
629673
}

0 commit comments

Comments
 (0)