diff --git a/server/identification.ts b/server/identification.ts index 1c01d793..03a29687 100644 --- a/server/identification.ts +++ b/server/identification.ts @@ -1,9 +1,9 @@ -import log from "./log"; import fs from "fs"; import net, {Socket} from "net"; import colors from "chalk"; import Helper from "./helper"; import Config from "./config"; +import log from "./log"; type Connection = { socket: Socket; @@ -66,31 +66,56 @@ class Identification { serverConnection(socket: Socket) { socket.on("error", (err: string) => log.error(`Identd socket error: ${err}`)); - socket.on("data", (data) => { + socket.setTimeout(5000, () => { + log.warn( + `identd: no data received, closing connection to ${ + socket.remoteAddress || "undefined" + }` + ); + socket.destroy(); + }); + socket.once("data", (data) => { this.respondToIdent(socket, data); socket.end(); }); } respondToIdent(socket: Socket, buffer: Buffer) { + if (!socket.remoteAddress) { + log.warn("identd: no remote address"); + return; + } + const data = buffer.toString().split(","); const lport = parseInt(data[0], 10) || 0; const fport = parseInt(data[1], 10) || 0; if (lport < 1 || fport < 1 || lport > 65535 || fport > 65535) { + log.warn(`identd: bogus request from ${socket.remoteAddress}`); return; } + log.debug(`identd: remote ${socket.remoteAddress} query ${lport}, ${fport}`); + for (const connection of this.connections.values()) { - if (connection.socket.remotePort === fport && connection.socket.localPort === lport) { - return socket.write( - `${lport}, ${fport} : USERID : TheLounge : ${connection.user}\r\n` - ); + // we only want to respond if all the ip,port tuples match, to avoid user enumeration + if ( + connection.socket.remotePort === fport && + connection.socket.localPort === lport && + socket.remoteAddress === connection.socket.remoteAddress && + socket.localAddress === connection.socket.localAddress + ) { + const reply = `${lport}, ${fport} : USERID : TheLounge : ${connection.user}\r\n`; + log.debug(`identd: reply is ${reply.trimEnd()}`); + socket.write(reply); + return; } } - socket.write(`${lport}, ${fport} : ERROR : NO-USER\r\n`); + const reply = `${lport}, ${fport} : ERROR : NO-USER\r\n`; + log.debug(`identd: reply is ${reply.trimEnd()}`); + socket.write(reply); } addSocket(socket: Socket, user: string) { @@ -127,8 +152,21 @@ class Identification { return; } + if (!connection.socket.remoteAddress) { + log.warn(`oidentd: socket has no remote address, will not respond to queries`); + return; + } + + if (!connection.socket.localAddress) { + log.warn(`oidentd: socket has no local address, will not respond to queries`); + return; + } + + // we only want to respond if all the ip,port tuples match, to avoid user enumeration file += - `fport ${connection.socket.remotePort}` + + `to ${connection.socket.remoteAddress}` + + ` fport ${connection.socket.remotePort}` + + ` from ${connection.socket.localAddress}` + ` lport ${connection.socket.localPort}` + ` { reply "${connection.user}" }\n`; });