// Kommt UDP aus diesem Container heraus? // // Discord-Sprache läuft über UDP auf hohen Zielports. Ist das dicht, sitzt // der Bot sichtbar im Sprachkanal und schweigt — im Log steht dann // „Der Austausch mit dem Sprachserver scheitert". // // Aufruf im Container: // docker exec -it node tools/udp-pruefen.mjs // // Geprüft wird in zwei Stufen, weil das den Unterschied ausmacht: // 1. UDP auf Port 53 (DNS) — geht überhaupt UDP raus? // 2. UDP auf einen hohen Port (STUN, 19302) — oder nur die üblichen? // // Beide grün und der Bot schweigt trotzdem? Dann liegt es nicht am UDP. import dgram from 'node:dgram'; /** Ein Paket hinschicken und auf Antwort warten */ function versuch({ host, port, paket, timeoutMs = 4000 }) { return new Promise((fertig) => { const sock = dgram.createSocket('udp4'); const start = Date.now(); const schluss = (ergebnis) => { clearTimeout(timer); try { sock.close(); } catch { /* schon zu */ } fertig(ergebnis); }; const timer = setTimeout(() => schluss({ ok: false, grund: 'keine Antwort' }), timeoutMs); sock.on('message', () => schluss({ ok: true, ms: Date.now() - start })); sock.on('error', (e) => schluss({ ok: false, grund: e.message })); sock.send(paket, port, host, (e) => { if (e) schluss({ ok: false, grund: `Senden ging nicht: ${e.message}` }); }); }); } // Eine DNS-Anfrage nach example.com — kürzestmöglich von Hand gebaut const dnsPaket = Buffer.concat([ Buffer.from([0x12, 0x34, 0x01, 0x00, 0, 1, 0, 0, 0, 0, 0, 0]), Buffer.from([7]), Buffer.from('example'), Buffer.from([3]), Buffer.from('com'), Buffer.from([0, 0, 1, 0, 1]), ]); // Eine STUN-Bindungsanfrage: 20 Byte Kopf, fester Magic Cookie const stunPaket = Buffer.concat([ Buffer.from([0x00, 0x01, 0x00, 0x00]), Buffer.from([0x21, 0x12, 0xa4, 0x42]), Buffer.from('d4rkbotudpprue'.slice(0, 12)), ]); const proben = [ { name: 'UDP raus (DNS)', host: '1.1.1.1', port: 53, paket: dnsPaket }, { name: 'UDP raus (DNS, zweiter)', host: '8.8.8.8', port: 53, paket: dnsPaket }, { name: 'UDP auf hohem Port (STUN)', host: 'stun.l.google.com', port: 19302, paket: stunPaket }, { name: 'UDP auf hohem Port (STUN 2)', host: 'stun1.l.google.com', port: 19302, paket: stunPaket }, ]; console.log('Prüfe ausgehendes UDP …\n'); const ergebnisse = []; for (const p of proben) { const r = await versuch(p); ergebnisse.push({ ...p, ...r }); console.log(` ${r.ok ? '✅' : '❌'} ${p.name.padEnd(28)} ${p.host}:${p.port} ` + (r.ok ? `${r.ms} ms` : r.grund)); } const niedrig = ergebnisse.filter((r) => r.port < 1024).some((r) => r.ok); const hoch = ergebnisse.filter((r) => r.port >= 1024).some((r) => r.ok); console.log(''); if (hoch) { console.log('UDP kommt auf hohen Ports raus. Wenn das Radio trotzdem schweigt,'); console.log('liegt es nicht an ausgehendem UDP — dann den Endpunkt aus dem Log'); console.log('mit dem nächsten Abschnitt prüfen.'); } else if (niedrig) { console.log('UDP geht nur auf niedrigen Ports raus. Genau das bricht Discord-Sprache:'); console.log('die Sprachserver antworten auf hohen Ports. In der Firewall ausgehendes'); console.log('UDP zu 50000–65535 freigeben.'); } else { console.log('Es kommt gar kein UDP heraus. Discord-Sprache kann so nicht funktionieren.'); console.log('Ausgehendes UDP in der Firewall des Rootservers freigeben.'); } // Endpunkt aus dem Log mitgeben: node tools/udp-pruefen.mjs frankfurt1234.discord.media const ziel = process.argv[2]; if (ziel) { console.log(`\nZusätzlich: ${ziel} auf Port 50000 …`); // Discord antwortet auf ein Zufallspaket nicht — hier zählt nur, ob das // Senden selbst durchgeht und ob eine Fehlermeldung zurückkommt. const r = await versuch({ host: ziel, port: 50000, paket: Buffer.alloc(74), timeoutMs: 3000 }); console.log(r.ok ? ' Antwort erhalten (ungewöhnlich, aber gut).' : ` ${r.grund === 'keine Antwort' ? 'keine Antwort — das ist hier normal, ein Fehler waere aussagekräftiger' : `Fehler: ${r.grund}`}`); }