mirror of
https://git.kernel.org/pub/scm/network/iproute2/iproute2.git
synced 2024-11-24 10:23:40 +08:00
271 lines
6.1 KiB
Plaintext
271 lines
6.1 KiB
Plaintext
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;
|
|
}
|
|
}
|