void NLSocket::process_receive(std::size_t bytes_xferred, unsigned int seq, unsigned int portid) { const struct nlmsghdr *nlh = (const struct nlmsghdr *)recv_buffer_.data(); for (;NLMSG_OK(nlh, bytes_xferred); nlh = NLMSG_NEXT(nlh, bytes_xferred)) { // Should be 0 for messages from the kernel. if (nlh->nlmsg_pid && portid && nlh->nlmsg_pid != portid) continue; if (seq && nlh->nlmsg_seq != seq) continue; if (nlh->nlmsg_type >= NLMSG_MIN_TYPE) { process_nlmsg(nlh); } else { switch (nlh->nlmsg_type) { case NLMSG_ERROR: { fmt::print(stderr, "nlsocket: Received a NLMSG_ERROR: {}\n", strerror(nlmsg_get_error(nlh))); auto nle = reinterpret_cast<struct nlmsgerr *>(NLMSG_DATA(nlh)); fmt::print(stderr, "error={} len={} type={} flags={} seq={} pid={}\n", nle->error, nle->msg.nlmsg_len, nle->msg.nlmsg_type, nle->msg.nlmsg_flags, nle->msg.nlmsg_seq, nle->msg.nlmsg_pid); break; } case NLMSG_OVERRUN: fmt::print(stderr, "nlsocket: Received a NLMSG_OVERRUN.\n"); case NLMSG_NOOP: case NLMSG_DONE: default: break; } } } }
static int process_response(int wait_for_done, unsigned seq) { assert(fd >= 0); do { size_t bytes; ssize_t r; char replybuf[8*1024]; char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; struct msghdr msghdr; struct cmsghdr *cmsghdr; struct ucred *ucred; struct iovec iov; struct nlmsghdr *p = (struct nlmsghdr *) replybuf; memset(&iov, 0, sizeof(iov)); iov.iov_base = replybuf; iov.iov_len = sizeof(replybuf); memset(&msghdr, 0, sizeof(msghdr)); msghdr.msg_name = (void*) NULL; msghdr.msg_namelen = 0; msghdr.msg_iov = &iov; msghdr.msg_iovlen = 1; msghdr.msg_control = cred_msg; msghdr.msg_controllen = sizeof(cred_msg); msghdr.msg_flags = 0; if ((r = recvmsg(fd, &msghdr, 0)) < 0) { daemon_log(LOG_ERR, "recvmsg() failed: %s", strerror(errno)); return -1; } if (!(cmsghdr = CMSG_FIRSTHDR(&msghdr)) || cmsghdr->cmsg_type != SCM_CREDENTIALS) { daemon_log(LOG_WARNING, "No sender credentials received, ignoring data."); return -1; } ucred = (struct ucred*) CMSG_DATA(cmsghdr); if (ucred->uid != 0) return -1; bytes = (size_t) r; for (; bytes > 0; p = NLMSG_NEXT(p, bytes)) { if (!NLMSG_OK(p, bytes) || bytes < sizeof(struct nlmsghdr) || bytes < p->nlmsg_len) { daemon_log(LOG_ERR, "Netlink packet too small."); return -1; } if (p->nlmsg_type == NLMSG_DONE && wait_for_done && p->nlmsg_seq == seq && (pid_t) p->nlmsg_pid == getpid()) return 0; if (p->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *e = (struct nlmsgerr *) NLMSG_DATA (p); if (e->error) { daemon_log(LOG_ERR, "Netlink error: %s", strerror(-e->error)); return -1; } } if (process_nlmsg(p) < 0) return -1; } } while (wait_for_done); return 0; }