UNPKG

penguins-eggs

Version:

A remaster system tool, compatible with Almalinux, Alpine, Arch, Debian, Devuan, Fedora, Manjaro, Opensuse, Ubuntu and derivatives

117 lines (116 loc) 5.46 kB
/** * simple-proxy.ts * Un proxy DHCP minimale che agisce come un mini-server DHCP completo * solo per i client PXE, per aggirare le protezioni di rete. */ import ansis from 'ansis'; import { createSocket } from 'dgram'; import { DhcpMessageType } from '../dhcpd-proxy//lib/packet/message-types.js'; import { Packet } from '../dhcpd-proxy/classes/packet.js'; // Un semplice Map in memoria per tracciare gli IP offerti const offeredIPs = new Map(); /** * La nostra unica funzione. Prende le opzioni e avvia il proxy. * @param options Le opzioni di configurazione PXE */ export function startSimpleProxy(options) { const socket = createSocket({ reuseAddr: true, type: 'udp4' }); socket.on('error', (err) => { console.error(ansis.red.bold(`ERRORE SOCKET: ${err.stack}`)); socket.close(); }); socket.on('listening', () => { const address = socket.address(); socket.setBroadcast(true); console.log(ansis.green.inverse(`\n Proxy DHCP listening su ${address.address}:${address.port}. CTRL-C to end!\n`)); }); socket.on('message', (buffer, rinfo) => { try { const packet = Packet.fromBuffer(buffer); packet.remote = rinfo; const messageType = packet.options[53] || 0; if (packet.op === 1 && messageType === DhcpMessageType.DHCPDISCOVER) { handleDiscover(packet, options); } else if (packet.op === 1 && messageType === DhcpMessageType.DHCPREQUEST) { handleRequest(packet, options); } } catch { // Ignoriamo errori di parsing } }); socket.bind(67, '0.0.0.0'); // --- Funzioni Helper Interne --- function setBootFilename(packet, opts) { const isIpxe = packet.options[77] && packet.options[77].toString().includes('iPXE'); const arch = packet.options[93] || packet.options[60]; const isUefi64 = arch && (String(arch).includes('00007') || String(arch).includes('00009')); // LOGICA DI ASSEGNAZIONE PRECISA if (isIpxe && isUefi64) { // CASO 1: Il client è iPXE e anche UEFI. Offriamo lo script! console.log(ansis.magenta.bold(`<- Rilevato client iPXE su UEFI! Offro script autoexec...`)); return `http://${opts.host}/autoexec.ipxe`; } if (isUefi64) { // CASO 2: Il client è UEFI ma non è ancora iPXE. Offriamo il bootloader iPXE per UEFI. return opts.efi64_filename; } // CASO 3: Il client è BIOS. Offriamo il bootloader iPXE per BIOS. // (Aggiunta logica per altri tipi di architettura se necessario) return opts.bios_filename; } function handleDiscover(packet, opts) { console.log(ansis.blue.bold(`\n-> DISCOVER Ricevuto`)); console.log(ansis.dim(` └─ Da MAC: ${ansis.white(packet.chaddr)}`)); if (packet.options[60]?.includes('PXEClient')) { console.log(ansis.cyan.bold(`<- Rilevato PXEClient! Preparo un'offerta completa...`)); const offerPacket = new Packet(packet); offerPacket.op = 2; // BOOTREPLY const ipParts = opts.host.split('.'); ipParts[3] = (Number.parseInt(ipParts[3]) + 10).toString(); const offeredIp = ipParts.join('.'); offeredIPs.set(packet.chaddr, offeredIp); offerPacket.yiaddr = offeredIp; offerPacket.siaddr = opts.tftpserver; offerPacket.options[53] = DhcpMessageType.DHCPOFFER; offerPacket.options[54] = opts.host; // Imposta il filename usando la nuova funzione logica offerPacket.fname = setBootFilename(packet, opts); console.log(ansis.dim(` ├─ Offro IP: ${ansis.green(offeredIp)}`)); console.log(ansis.dim(` ├─ Next-Server: ${ansis.white(offerPacket.siaddr)}`)); console.log(ansis.dim(` └─ Filename: ${ansis.white(offerPacket.fname)}`)); send(offerPacket, opts.broadcast, 68); } } function handleRequest(packet, opts) { const offeredIp = offeredIPs.get(packet.chaddr); if (!offeredIp || (packet.options[50] && packet.options[50] !== offeredIp)) { return; } console.log(ansis.yellow.bold(`-> REQUEST per la nostra offerta ricevuto!`)); console.log(ansis.dim(` └─ Da MAC: ${ansis.white(packet.chaddr)}`)); const ackPacket = new Packet(packet); ackPacket.op = 2; ackPacket.yiaddr = offeredIp; ackPacket.siaddr = opts.tftpserver; ackPacket.options[53] = DhcpMessageType.DHCPACK; ackPacket.options[54] = opts.host; // Imposta il filename usando la stessa logica ackPacket.fname = setBootFilename(packet, opts); console.log(ansis.cyan.bold(`<- Invio ACK finale...`)); send(ackPacket, opts.broadcast, 68); } function send(packet, ip, port) { const buffer = packet.toBuffer(); const typeName = DhcpMessageType[packet.options[53]] || 'UNKNOWN'; socket.send(buffer, 0, buffer.length, port, ip, (err, bytes) => { if (err) { console.error(ansis.red.bold(`[PROXY-ERROR] Errore invio ${typeName}:`), err); } else { console.log(ansis.green(` ✔︎ ${typeName} inviata a ${ip}:${port} (${bytes} bytes)`)); } }); } }