--- pidentd-3.0.19.ds1.orig/src/k_linux.c
+++ pidentd-3.0.19.ds1/src/k_linux.c
@@ -17,15 +17,28 @@
#include <stdio.h>
#include <syslog.h>
#include <errno.h>
+#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#include <netinet/tcp.h>
#include <arpa/inet.h>
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include <linux/inet_diag.h>
+
#include "pidentd.h"
+struct kainfo
+{
+ int nlfd;
+ __u32 seq;
+ FILE *proc_net_tcp;
+};
+
/*
** Make sure we are running on a supported OS version
*/
@@ -39,23 +52,85 @@
int
ka_open(void **misc)
{
- FILE *fp;
+ struct kainfo *kp;
+
+ kp = s_malloc(sizeof(*kp));
+ kp->seq = 0;
+ kp->nlfd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_INET_DIAG);
+ if (kp->nlfd >= 0)
+ goto out;
- while ((fp = fopen("/proc/net/tcp", "r")) == NULL && errno == EINTR)
- ;
+ syslog(LOG_INFO, "netlink failed, fallback to /proc/net/tcp: %m");
+ kp->proc_net_tcp = fopen("/proc/net/tcp", "r");
- if (fp == NULL)
+ if (kp->proc_net_tcp == NULL)
{
syslog(LOG_ERR, "fopen(\"/proc/net/tcp\", \"r\"): %m");
return -1;
}
- *misc = (void *) fp;
+out:
+ *misc = (void *) kp;
return 0;
}
+static int
+netlink_lookup(struct kainfo *kip, struct kernel *kp)
+{
+ int status;
+ struct {
+ struct nlmsghdr nlh;
+ union {
+ struct inet_diag_req req;
+ struct inet_diag_msg rsp;
+ } u;
+ } buf;
+ struct sockaddr_nl addr;
+
+ memset(&buf, 0, sizeof(buf));
+ buf.nlh.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(buf.u.req)));
+ buf.nlh.nlmsg_type = TCPDIAG_GETSOCK;
+ buf.nlh.nlmsg_flags = NLM_F_REQUEST;
+ buf.nlh.nlmsg_seq = ++kip->seq;
+ buf.u.req.idiag_family = AF_INET;
+
+ buf.u.req.id.idiag_dport = kp->remote.sin_port;
+ buf.u.req.id.idiag_sport = kp->local.sin_port;
+ buf.u.req.id.idiag_dst[0] = kp->remote.sin_addr.s_addr;
+ buf.u.req.id.idiag_src[0] = kp->local.sin_addr.s_addr;
+ buf.u.req.id.idiag_cookie[0] = INET_DIAG_NOCOOKIE;
+ buf.u.req.id.idiag_cookie[1] = INET_DIAG_NOCOOKIE;
+
+ status = write(kip->nlfd, &buf, buf.nlh.nlmsg_len);
+ if (status < 0) {
+ syslog(LOG_ERR, "netlink_lookup: write failed: %m");
+ return 3;
+ }
+
+ do {
+ socklen_t alen = sizeof(addr);
+ status = recvfrom(kip->nlfd, &buf, sizeof(buf), 0,
+ (void *)&addr, &alen);
+ if (status < 0) {
+ if (errno == ENOBUFS)
+ return -1;
+ syslog(LOG_ERR, "netlink_lookup: recvfrom failed: %m");
+ return 3;
+ }
+ } while (addr.nl_pid || buf.nlh.nlmsg_seq != kip->seq);
+
+ if (buf.nlh.nlmsg_type != TCPDIAG_GETSOCK)
+ return 0;
+ if (buf.u.rsp.idiag_state != TCP_ESTABLISHED)
+ return 0;
+
+ kp->euid = buf.u.rsp.idiag_uid;
+ return 1;
+}
+
+
int
ka_lookup(void *vp, struct kernel *kp)
{
@@ -66,6 +141,9 @@
int r_lport, r_rport, mylport, myrport;
int euid;
int nra;
+ int status;
+ unsigned long ino;
+ struct kainfo *kip;
/*
* PSz 11 Dec 02
@@ -94,23 +172,28 @@
*
* Should we skip lines with just ino, or both uid and ino, zero?
*/
- unsigned long int ino;
-
+
+ kip = (struct kainfo *)vp;
+ kp->ruid = NO_UID;
+
+ if (kip->nlfd >= 0)
+ return netlink_lookup(kip, kp);
+
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;
- fp = (FILE *) vp;
+ fp = kip->proc_net_tcp;
- kp->ruid = NO_UID;
rewind(fp);
/* eat header */
if (fgets(buf, sizeof(buf)-1,fp) == NULL)
return -1;
+ status = 0;
while (fgets(buf, sizeof(buf)-1, fp) != NULL)
{
nra = sscanf(buf, "%d: %lX:%x %lX:%x %x %lX:%lX %x:%lX %lx %d %ld %lu",
@@ -119,9 +202,10 @@
&euid, &dummy, &ino);
if (nra >= 12)
{
- if (myladdr == r_laddr && mylport == r_lport &&
- myraddr == r_raddr && myrport == r_rport)
+ if (myladdr == r_laddr && mylport == r_lport)
{
+ if (myraddr != r_raddr || myrport != r_rport || !ino)
+ continue;
if (nra >= 14 && euid == 0 && ino == 0) {
/*
* Both uid and ino are zero: not even a socket?
@@ -131,11 +215,11 @@
continue;
}
kp->euid = euid;
- return 1;
+ status = 1;
}
}
}
- return -1;
+ return status;
}