--- ./slpd/slpd_database.c.orig 2014-02-19 18:04:09.926934782 +0000 +++ ./slpd/slpd_database.c 2014-02-19 18:04:34.553934738 +0000 @@ -50,6 +50,10 @@ #define _GNU_SOURCE #include #include +#include +#include +#include +#include #include "../libslpattr/libslpattr.h" #include "slpd_database.h" @@ -1919,6 +1923,168 @@ int SLPDDatabaseReInit() return 0; } +enum { + SS_UNKNOWN, + SS_ESTABLISHED, + SS_SYN_SENT, + SS_SYN_RECV, + SS_FIN_WAIT1, + SS_FIN_WAIT2, + SS_TIME_WAIT, + SS_CLOSE, + SS_CLOSE_WAIT, + SS_LAST_ACK, + SS_LISTEN, + SS_CLOSING, + SS_MAX +}; + +#define SS_ALL ((1< 0) { + if (sendmsg(*fd, &msg, 0) >= 0) + break; + + if (reconnect_nl(fd)) { + SLPDLog("Lost TCPDIAG netlink connection and attempts to " + "re-establish have failed. Falling back to /proc/net/tcp " + "for dead/alive updates.\n"); + *fd = -1; + return; + } + sched_yield(); + } + + iov.iov_base = buf; + iov.iov_len = sizeof(buf); + + dh = SLPDatabaseOpen(&G_SlpdDatabase.database); + while (!status) { + struct nlmsghdr *h; + + status = recvmsg(*fd, &msg, 0); + if (status < 0) { + if (errno == EINTR) + continue; + goto retry_sendmsg; + } + + /* Socket has shut down */ + if (status == 0) + goto retry_sendmsg; + + for (h = (struct nlmsghdr *) buf; NLMSG_OK(h, status); + h = NLMSG_NEXT(h, status)) { + SLPDatabaseEntry *entry; + struct inet_diag_msg *r = NLMSG_DATA(h); + + if (h->nlmsg_seq != 123456) + continue; + + if (h->nlmsg_type == NLMSG_DONE) + goto close; + + if (h->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *err = NLMSG_DATA(h); + if (h->nlmsg_len >= NLMSG_LENGTH(sizeof(*err))) + status = EINVAL; + else + status = -err->error; + break; + } + + if (r->idiag_family != AF_INET && r->idiag_family != AF_INET6) + continue; + + if (r->idiag_family == AF_INET && + ipv4_loopback.s_addr == r->id.idiag_src[0]) + continue; + + if (r->idiag_family == AF_INET6 && + !memcmp(ipv6_loopback.s6_addr32, r->id.idiag_src, + sizeof(ipv6_loopback))) + continue; + + port = ntohs(r->id.idiag_sport); + if (!(porthash[(port / 8) & 255] & (1 << (port & 7)))) + continue; + + SLPDatabaseRewind(dh); + + while ((entry = SLPDatabaseEnum(dh)) != 0) { + SLPSrvReg *srvreg = &(entry->msg->body.srvreg); + if (!(srvreg->watchflags & flag)) + continue; + if (port == srvreg->watchport) + srvreg->watchflags &= ~SLP_REG_WATCH_CHECKING; + } + } + } + +close: + SLPDatabaseClose(dh); +} + static void SLPDDatabaseWatcher_fd(int fd, int flag, unsigned char *porthash) { SLPDatabaseHandle dh; @@ -1978,7 +2144,7 @@ static void SLPDDatabaseWatcher_fd(int f void SLPDDatabaseWatcher(void) { static int initialized = 0; - static int proctcp, procudp, proctcp6, procudp6; + static int proctcp, procudp, proctcp6, procudp6, inet_diag = -1; unsigned char porthash[256]; int flags, port; SLPDatabaseHandle dh; @@ -1986,6 +2152,7 @@ void SLPDDatabaseWatcher(void) SLPSrvReg* srvreg; if (!initialized) { + inet_diag = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG); proctcp = open("/proc/net/tcp_listen", O_RDONLY); if (proctcp == -1) proctcp = open("/proc/net/tcp", O_RDONLY); @@ -2010,8 +2177,12 @@ void SLPDDatabaseWatcher(void) } SLPDatabaseClose(dh); if ((flags & SLP_REG_WATCH_TCP) != 0) { - SLPDDatabaseWatcher_fd(proctcp, SLP_REG_WATCH_TCP, porthash); - SLPDDatabaseWatcher_fd(proctcp6, SLP_REG_WATCH_TCP, porthash); + if (inet_diag >= 0) + SLPDDatabaseWatcher_nl(&inet_diag, SLP_REG_WATCH_TCP, porthash); + if (inet_diag < 0) { /* Fallback if _nl fails */ + SLPDDatabaseWatcher_fd(proctcp, SLP_REG_WATCH_TCP, porthash); + SLPDDatabaseWatcher_fd(proctcp6, SLP_REG_WATCH_TCP, porthash); + } } if ((flags & SLP_REG_WATCH_UDP) != 0) { SLPDDatabaseWatcher_fd(procudp, SLP_REG_WATCH_UDP, porthash);