|
| 1 | +import * as net from 'net'; |
| 2 | +import {RmRecordDecoder} from '../../../rm'; |
| 3 | +import {RpcMessageDecoder, RpcCallMessage} from '../../../rpc'; |
| 4 | +import {Nfsv4Decoder} from '../Nfsv4Decoder'; |
| 5 | +import * as msg from '../messages'; |
| 6 | +import {Nfsv4Op} from '../constants'; |
| 7 | + |
| 8 | +/* tslint:disable:no-console */ |
| 9 | + |
| 10 | +const PORT = Number(process.env.PORT) || 2049; |
| 11 | +const HOST = '127.0.0.1'; |
| 12 | + |
| 13 | +const toHex = (buffer: Uint8Array | Buffer): string => { |
| 14 | + return Array.from(buffer) |
| 15 | + .map((byte) => byte.toString(16).padStart(2, '0')) |
| 16 | + .join(''); |
| 17 | +}; |
| 18 | + |
| 19 | +const getProcName = (proc: number): string => { |
| 20 | + const names: Record<number, string> = { |
| 21 | + 0: 'NULL', |
| 22 | + 1: 'COMPOUND', |
| 23 | + }; |
| 24 | + return names[proc] || `UNKNOWN(${proc})`; |
| 25 | +}; |
| 26 | + |
| 27 | +const getOpName = (op: any): string => { |
| 28 | + if (op instanceof msg.Nfsv4AccessRequest) return 'ACCESS'; |
| 29 | + if (op instanceof msg.Nfsv4CloseRequest) return 'CLOSE'; |
| 30 | + if (op instanceof msg.Nfsv4CommitRequest) return 'COMMIT'; |
| 31 | + if (op instanceof msg.Nfsv4CreateRequest) return 'CREATE'; |
| 32 | + if (op instanceof msg.Nfsv4DelegpurgeRequest) return 'DELEGPURGE'; |
| 33 | + if (op instanceof msg.Nfsv4DelegreturnRequest) return 'DELEGRETURN'; |
| 34 | + if (op instanceof msg.Nfsv4GetattrRequest) return 'GETATTR'; |
| 35 | + if (op instanceof msg.Nfsv4GetfhRequest) return 'GETFH'; |
| 36 | + if (op instanceof msg.Nfsv4LinkRequest) return 'LINK'; |
| 37 | + if (op instanceof msg.Nfsv4LockRequest) return 'LOCK'; |
| 38 | + if (op instanceof msg.Nfsv4LocktRequest) return 'LOCKT'; |
| 39 | + if (op instanceof msg.Nfsv4LockuRequest) return 'LOCKU'; |
| 40 | + if (op instanceof msg.Nfsv4LookupRequest) return 'LOOKUP'; |
| 41 | + if (op instanceof msg.Nfsv4LookuppRequest) return 'LOOKUPP'; |
| 42 | + if (op instanceof msg.Nfsv4NverifyRequest) return 'NVERIFY'; |
| 43 | + if (op instanceof msg.Nfsv4OpenRequest) return 'OPEN'; |
| 44 | + if (op instanceof msg.Nfsv4OpenattrRequest) return 'OPENATTR'; |
| 45 | + if (op instanceof msg.Nfsv4OpenConfirmRequest) return 'OPEN_CONFIRM'; |
| 46 | + if (op instanceof msg.Nfsv4OpenDowngradeRequest) return 'OPEN_DOWNGRADE'; |
| 47 | + if (op instanceof msg.Nfsv4PutfhRequest) return 'PUTFH'; |
| 48 | + if (op instanceof msg.Nfsv4PutpubfhRequest) return 'PUTPUBFH'; |
| 49 | + if (op instanceof msg.Nfsv4PutrootfhRequest) return 'PUTROOTFH'; |
| 50 | + if (op instanceof msg.Nfsv4ReadRequest) return 'READ'; |
| 51 | + if (op instanceof msg.Nfsv4ReaddirRequest) return 'READDIR'; |
| 52 | + if (op instanceof msg.Nfsv4ReadlinkRequest) return 'READLINK'; |
| 53 | + if (op instanceof msg.Nfsv4RemoveRequest) return 'REMOVE'; |
| 54 | + if (op instanceof msg.Nfsv4RenameRequest) return 'RENAME'; |
| 55 | + if (op instanceof msg.Nfsv4RenewRequest) return 'RENEW'; |
| 56 | + if (op instanceof msg.Nfsv4RestorefhRequest) return 'RESTOREFH'; |
| 57 | + if (op instanceof msg.Nfsv4SavefhRequest) return 'SAVEFH'; |
| 58 | + if (op instanceof msg.Nfsv4SecinfoRequest) return 'SECINFO'; |
| 59 | + if (op instanceof msg.Nfsv4SetattrRequest) return 'SETATTR'; |
| 60 | + if (op instanceof msg.Nfsv4SetclientidRequest) return 'SETCLIENTID'; |
| 61 | + if (op instanceof msg.Nfsv4SetclientidConfirmRequest) return 'SETCLIENTID_CONFIRM'; |
| 62 | + if (op instanceof msg.Nfsv4VerifyRequest) return 'VERIFY'; |
| 63 | + if (op instanceof msg.Nfsv4WriteRequest) return 'WRITE'; |
| 64 | + if (op instanceof msg.Nfsv4ReleaseLockOwnerRequest) return 'RELEASE_LOCKOWNER'; |
| 65 | + if (op instanceof msg.Nfsv4IllegalRequest) return 'ILLEGAL'; |
| 66 | + return 'UNKNOWN'; |
| 67 | +}; |
| 68 | + |
| 69 | +const server = net.createServer((socket) => { |
| 70 | + console.log(`[${new Date().toISOString()}] Client connected from ${socket.remoteAddress}:${socket.remotePort}`); |
| 71 | + const rmDecoder = new RmRecordDecoder(); |
| 72 | + const rpcDecoder = new RpcMessageDecoder(); |
| 73 | + const nfsDecoder = new Nfsv4Decoder(); |
| 74 | + socket.on('data', (data) => { |
| 75 | + console.log('\n' + '='.repeat(80)); |
| 76 | + console.log(`[${new Date().toISOString()}] Received ${data.length} bytes`); |
| 77 | + console.log('HEX:', toHex(data)); |
| 78 | + console.log('-'.repeat(80)); |
| 79 | + const uint8Data = new Uint8Array(data); |
| 80 | + rmDecoder.push(uint8Data); |
| 81 | + let record = rmDecoder.readRecord(); |
| 82 | + while (record) { |
| 83 | + console.log(`\nRPC Record (${record.size()} bytes):`); |
| 84 | + console.log('HEX:', toHex(record.subarray())); |
| 85 | + const rpcMessage = rpcDecoder.decodeMessage(record); |
| 86 | + if (rpcMessage) { |
| 87 | + console.log('\nRPC Message:'); |
| 88 | + console.log(rpcMessage); |
| 89 | + if (rpcMessage instanceof RpcCallMessage) { |
| 90 | + const proc = rpcMessage.proc; |
| 91 | + console.log(`\nNFS Procedure: ${getProcName(proc)}`); |
| 92 | + if (rpcMessage.params) { |
| 93 | + if (proc === 1) { |
| 94 | + const compound = nfsDecoder.decodeCompound(rpcMessage.params, true); |
| 95 | + if (compound && 'argarray' in compound) { |
| 96 | + console.log('\nNFS COMPOUND Request:'); |
| 97 | + console.log(` Tag: "${compound.tag}"`); |
| 98 | + console.log(` Minor Version: ${compound.minorversion}`); |
| 99 | + console.log(` Operations (${compound.argarray.length}):`); |
| 100 | + compound.argarray.forEach((op: any, idx: number) => { |
| 101 | + console.log(` [${idx}] ${getOpName(op)}`); |
| 102 | + console.log(` ${JSON.stringify(op, null, 2).split('\n').slice(1).join('\n ')}`); |
| 103 | + }); |
| 104 | + } else { |
| 105 | + console.log('Could not decode COMPOUND request'); |
| 106 | + } |
| 107 | + } else if (proc === 0) { |
| 108 | + console.log('NULL procedure (no parameters)'); |
| 109 | + } else { |
| 110 | + console.log(`Unknown procedure: ${proc}`); |
| 111 | + } |
| 112 | + } |
| 113 | + } |
| 114 | + } else { |
| 115 | + console.log('Could not decode RPC message'); |
| 116 | + } |
| 117 | + record = rmDecoder.readRecord(); |
| 118 | + } |
| 119 | + console.log('='.repeat(80) + '\n'); |
| 120 | + }); |
| 121 | + socket.on('end', () => { |
| 122 | + console.log(`[${new Date().toISOString()}] Client disconnected`); |
| 123 | + }); |
| 124 | + socket.on('error', (err) => { |
| 125 | + console.error(`[${new Date().toISOString()}] Socket error:`, err.message); |
| 126 | + }); |
| 127 | +}); |
| 128 | + |
| 129 | +server.on('error', (err) => { |
| 130 | + console.error('Server error:', err.message); |
| 131 | + process.exit(1); |
| 132 | +}); |
| 133 | + |
| 134 | +server.listen(PORT, HOST, () => { |
| 135 | + console.log(`NFSv4 TCP Server listening on ${HOST}:${PORT}`); |
| 136 | + console.log('Waiting for connections...\n'); |
| 137 | +}); |
| 138 | + |
| 139 | +process.on('SIGINT', () => { |
| 140 | + console.log('\nShutting down server...'); |
| 141 | + server.close(() => { |
| 142 | + console.log('Server closed'); |
| 143 | + process.exit(0); |
| 144 | + }); |
| 145 | +}); |
0 commit comments