+diff -ur ../pidentd-3.0.12-orig/src/k_linux.c ./src/k_linux.c
+--- ../pidentd-3.0.12-orig/src/k_linux.c Sat Jan 12 00:44:05 2002
++++ ./src/k_linux.c Sat Nov 3 07:51:28 2001
+@@ -26,12 +26,65 @@
+
+ #include "pidentd.h"
+
++#define NETLINK_TCPDIAG 4
++#define TCPDIAG_GETSOCK 18
++
++#include <linux/uio.h>
++#include <linux/netlink.h>
++
++/* Socket identity */
++struct tcpdiag_sockid
++{
++ __u16 tcpdiag_sport;
++ __u16 tcpdiag_dport;
++ __u32 tcpdiag_src[4];
++ __u32 tcpdiag_dst[4];
++ __u32 tcpdiag_if;
++ __u32 tcpdiag_cookie[2];
++#define TCPDIAG_NOCOOKIE (~0U)
++};
++
++/* Request structure */
++
++struct tcpdiagreq
++{
++ __u8 tcpdiag_family; /* Family of addresses. */
++ __u8 tcpdiag_src_len;
++ __u8 tcpdiag_dst_len;
++ __u8 tcpdiag_ext; /* Query extended information */
++
++ struct tcpdiag_sockid id;
++
++ __u32 tcpdiag_states; /* States to dump */
++ __u32 tcpdiag_dbs; /* Tables to dump (NI) */
++};
++
++struct tcpdiagmsg
++{
++ __u8 tcpdiag_family;
++ __u8 tcpdiag_state;
++ __u8 tcpdiag_timer;
++ __u8 tcpdiag_retrans;
++
++ struct tcpdiag_sockid id;
++
++ __u32 tcpdiag_expires;
++ __u32 tcpdiag_rqueue;
++ __u32 tcpdiag_wqueue;
++ __u32 tcpdiag_uid;
++ __u32 tcpdiag_inode;
++};
++
++
++int tcpdiag_fd = -1;
++
+ /*
+ ** Make sure we are running on a supported OS version
+ */
+ int
+ ka_init(void)
+ {
++ tcpdiag_fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_TCPDIAG);
+ return 0; /* We always succeed */
+ }
+
+@@ -56,6 +109,144 @@
+ }
+
+
++
++int k_lookup_tcpdiag(struct kernel *kp)
++{
++ struct sockaddr_nl nladdr;
++ struct {
++ struct nlmsghdr nlh;
++ struct tcpdiagreq r;
++ } req;
++ struct msghdr msg;
++ char buf[8192];
++ struct iovec iov[1];
++ struct tcpdiagmsg *r;
++ static unsigned seqno = 123456;
++
++ memset(&nladdr, 0, sizeof(nladdr));
++ nladdr.nl_family = AF_NETLINK;
++
++ req.nlh.nlmsg_len = sizeof(req);
++ req.nlh.nlmsg_type = TCPDIAG_GETSOCK;
++ req.nlh.nlmsg_flags = NLM_F_REQUEST;
++ req.nlh.nlmsg_pid = 0;
++ req.nlh.nlmsg_seq = ++seqno;
++ memset(&req.r, 0, sizeof(req.r));
++ req.r.tcpdiag_family = AF_INET;
++ req.r.tcpdiag_states = ~0;
++
++ req.r.id.tcpdiag_dport = kp->remote.sin_port;
++ req.r.id.tcpdiag_sport = kp->local.sin_port;
++ req.r.id.tcpdiag_dst[0] = kp->remote.sin_addr.s_addr;
++ req.r.id.tcpdiag_src[0] = kp->local.sin_addr.s_addr;
++ req.r.id.tcpdiag_cookie[0] = TCPDIAG_NOCOOKIE;
++ req.r.id.tcpdiag_cookie[1] = TCPDIAG_NOCOOKIE;
++ kp->ruid = NO_UID;
++
++ iov[0] = (struct iovec){ &req, sizeof(req) };
++
++ msg = (struct msghdr) {
++ (void*)&nladdr, sizeof(nladdr),
++ iov, 1,
++ NULL, 0,
++ 0
++ };
++
++ if (sendmsg(tcpdiag_fd, &msg, 0) < 0) {
++ if (errno == ECONNREFUSED) {
++ close(tcpdiag_fd);
++ tcpdiag_fd = -1;
++ return 0;
++ }
++ syslog(LOG_ERR, "system error on tcpdiag sendmsg: %m");
++ return -1;
++ }
++
++ iov[0] = (struct iovec){ buf, sizeof(buf) };
++
++ while (1) {
++ int status;
++ struct nlmsghdr *h;
++
++ msg = (struct msghdr) {
++ (void*)&nladdr, sizeof(nladdr),
++ iov, 1,
++ NULL, 0,
++ 0
++ };
++
++ status = recvmsg(tcpdiag_fd, &msg, 0);
++
++ if (status < 0) {
++ if (errno == EINTR || errno == EAGAIN)
++ continue;
++ return -1;
++ }
++ if (status == 0) {
++ return -1;
++ }
++
++ h = (struct nlmsghdr*)buf;
++ while (NLMSG_OK(h, status)) {
++ int err;
++
++ if (/*h->nlmsg_pid != rth->local.nl_pid ||*/
++ h->nlmsg_seq != seqno)
++ goto skip_it;
++
++ if (h->nlmsg_type == NLMSG_DONE)
++ return -1;
++ if (h->nlmsg_type == NLMSG_ERROR) {
++ struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
++ if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
++ return -1;
++ } else {
++ errno = -err->error;
++ if (errno == ECONNREFUSED) {
++ close(tcpdiag_fd);
++ tcpdiag_fd = -1;
++ return 0;
++ }
++ if (errno != ENOENT)
++ syslog(LOG_ERR, "tcpdiag answers: %m");
++ }
++ return -1;
++ }
++
++ r = NLMSG_DATA(h);
++
++ /* Lookup _may_ return listening socket, if no
++ * better matches are found. */
++ if (r->id.tcpdiag_dport == kp->remote.sin_port &&
++ r->id.tcpdiag_dst[0] == kp->remote.sin_addr.s_addr) {
++ kp->ruid = r->tcpdiag_uid;
++ if (!r->tcpdiag_inode && !r->tcpdiag_uid) {
++ /* _NEVER_ return "root" for closed
++ * sockets. Otherwise people think
++ * that it is sysadmin who abuses their
++ * poor ircd. :-) */
++ syslog(LOG_NOTICE,
++ "Req for stale socket(%d) %d from %x/%d",
++ r->tcpdiag_state, ntohs(r->id.tcpdiag_sport),
++ r->id.tcpdiag_dst[0], ntohs(r->id.tcpdiag_dport));
++ return -1;
++ }
++ return 1;
++ }
++
++ return -1;
++
++skip_it:
++ h = NLMSG_NEXT(h, status);
++ }
++ if ((msg.msg_flags & MSG_TRUNC) || status) {
++ syslog(LOG_ERR, "truncated tcp_diag message");
++ return -1;
++ }
++ }
++}
++
++
+ int
+ ka_lookup(void *vp, struct kernel *kp)
+ {
+@@ -64,16 +255,23 @@
+ long r_laddr, r_raddr, myladdr, myraddr;
+ int r_lport, r_rport, mylport, myrport;
+ int euid;
+-
+-
++
++ if (tcpdiag_fd >= 0) {
++ int res;
++ if ((res = k_lookup_tcpdiag(kp)) != 0)
++ return res;
++ syslog(LOG_ERR, "tcp_diag is not loaded, fallback to proc");
++ }
++
++
+ r_rport = ntohs(kp->remote.sin_port);
+ r_lport = ntohs(kp->local.sin_port);
+ r_raddr = kp->remote.sin_addr.s_addr;
+ r_laddr = kp->local.sin_addr.s_addr;
++ kp->ruid = NO_UID;
+
+ fp = (FILE *) vp;
+
+- kp->ruid = NO_UID;
+ rewind(fp);
+
+ /* eat header */
+@@ -82,13 +280,26 @@
+
+ while (fgets(buf, sizeof(buf)-1, fp) != NULL)
+ {
+- if (sscanf(buf, "%*d: %lx:%x %lx:%x %*x %*x:%*x %*x:%*x %*x %d %*d %*d",
+- &myladdr, &mylport, &myraddr, &myrport, &euid) == 5)
++ int state, ino;
++ if (sscanf(buf, "%*d: %x:%x %x:%x %x %*x:%*x %*x:%*x %*x %d %*d %u",
++ &myladdr, &mylport, &myraddr, &myrport,
++ &state, &euid, &ino) == 7)
+ {
+ if (myladdr == r_laddr && mylport == r_lport &&
+ myraddr == r_raddr && myrport == r_rport)
+ {
+ kp->euid = euid;
++ if (ino == 0 && euid == 0)
++ {
++ /* _NEVER_ return "root" for closed
++ * sockets. Otherwise people think
++ * that it is sysadmin who abuses their
++ * poor ircd. :-) */
++ syslog(LOG_NOTICE,
++ "Req for stale socket(%d) %d from %x/%d",
++ state, r_rport, r_raddr, r_lport);
++ return -1;
++ }
+ return 1;
+ }
+ }