Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12:Update
openslp.3206
openslp.netlink.diff
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File openslp.netlink.diff of Package openslp.3206
--- ./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 <string.h> #include <dirent.h> +#include <sys/socket.h> +#include <linux/netlink.h> +#include <linux/inet_diag.h> +#include <sched.h> #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<<SS_MAX)-1) + +static int reconnect_nl(int *fd) +{ + int new_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG); + close (*fd); + if (new_fd < 0) + return errno; + *fd = new_fd; + return 0; +} + +static void SLPDDatabaseWatcher_nl(int *fd, int flag, unsigned char *porthash) +{ + char buf[8192]; + int port, status = 0; + SLPDatabaseHandle dh; + + struct sockaddr_nl nladdr = { + .nl_family = AF_NETLINK + }; + + struct { + struct nlmsghdr nlh; + struct inet_diag_req r; + } req = { + .nlh = { + .nlmsg_len = sizeof(req), + .nlmsg_type = TCPDIAG_GETSOCK, + .nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST, + .nlmsg_pid = 0, + .nlmsg_seq = 123456, + }, + .r = { + .idiag_family = AF_INET, + .idiag_states = 1 << SS_LISTEN, + .idiag_ext = ((1 << (INET_DIAG_INFO - 1)) | + (1 << (INET_DIAG_VEGASINFO - 1)) | + (1 << (INET_DIAG_CONG - 1))), + } + }; + + struct iovec iov = { + .iov_base = &req, + .iov_len = sizeof(req), + }; + + struct msghdr msg = { + .msg_name = (void *)&nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + struct in_addr ipv4_loopback = { htonl(INADDR_LOOPBACK) }; + struct in6_addr ipv6_loopback = IN6ADDR_LOOPBACK_INIT; + int retries; + + /* If the socket shuts down for whatever reason, we need to + * reopen it. Since we can't listen to a socket for which we have + * made a request, we reissue the request and listen again. */ +retry_sendmsg: + retries = 2; + while (retries-- > 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);
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor