Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Identd: fix various issues #4872

Merged
merged 4 commits into from
May 12, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
54 changes: 46 additions & 8 deletions server/identification.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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
) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ignores ipv4 in ipv6 handling...
Meaning if for some reason our ident server listens on ipv6 (dual stack) but the IRC connection is in ipv4 we will wrongly send an not found response.

Considering that you have to try rather hard to get to that edge case, I chose not to care.

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) {
Expand Down Expand Up @@ -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`;
});
Expand Down