/** * nfnl_query - request/response communication challenge * @h: nfnetlink handler * @nlh: nfnetlink message to be sent * * This function sends a nfnetlink message to a certain subsystem and * receives the response messages associated, such messages are passed to * the callback registered via register_callback(). Note that this function * is a replacement for nfnl_talk, its use is recommended. * * On success, 0 is returned. On error, a negative is returned. If your * does not want to listen to events anymore, then your callback must * return NFNL_CB_STOP. * * Note that ENOBUFS is returned in case that nfnetlink is exhausted. In * that case is possible that the information requested is incomplete. */ int nfnl_query(struct nfnl_handle *h, struct nlmsghdr *nlh) { assert(h); assert(nlh); if (nfnl_send(h, nlh) == -1) return -1; return nfnl_catch(h); }
/** * nfexp_send - send a query to ctnetlink * \param h library handler * \param qt query type * \param data data required to send the query * * Like nfexp_query but we do not wait for the reply from ctnetlink. * You can use nfexp_send() and nfexp_catch() to emulate nfexp_query(). * This is particularly useful when the socket is non-blocking. * * On error, -1 is returned and errno is explicitely set. On success, 0 * is returned. */ int nfexp_send(struct nfct_handle *h, const enum nf_conntrack_query qt, const void *data) { const size_t size = 4096; /* enough for now */ union { char buffer[size]; struct nfnlhdr req; } u; assert(h != NULL); assert(data != NULL); if (__build_query_exp(h->nfnlssh_exp, qt, data, &u.req, size) == -1) return -1; return nfnl_send(h->nfnlh, &u.req.nlh); }
/** * nfnl_catch - get responses from the nfnetlink system and process them * @h: nfnetlink handler * * This function handles the data received from the nfnetlink system. * For example, events generated by one of the subsystems. The message * is passed to the callback registered via callback_register(). Note that * this a replacement of nfnl_listen and its use is recommended. * * On success, 0 is returned. On error, a -1 is returned. If you do not * want to listen to events anymore, then your callback must return * NFNL_CB_STOP. * * Note that ENOBUFS is returned in case that nfnetlink is exhausted. In * that case is possible that the information requested is incomplete. */ int nfnl_catch(struct nfnl_handle *h) { int ret; unsigned int size = NFNL_BUFFSIZE; assert(h); /* * Since nfqueue can send big packets, we don't know how big * must be the buffer that have to store the received data. */ { unsigned char buf[size]; struct sockaddr_nl peer; struct iovec iov = { .iov_len = size, }; struct msghdr msg = { .msg_name = (void *) &peer, .msg_namelen = sizeof(peer), .msg_iov = &iov, .msg_iovlen = 1, .msg_control = NULL, .msg_controllen = 0, .msg_flags = 0 }; memset(&peer, 0, sizeof(peer)); peer.nl_family = AF_NETLINK; iov.iov_base = buf; iov.iov_len = size; retry: ret = recvmsg(h->fd, &msg, MSG_PEEK); if (ret == -1) { /* interrupted syscall must retry */ if (errno == EINTR) goto retry; /* otherwise give up */ return -1; } if (msg.msg_flags & MSG_TRUNC) /* maximum size of data received from netlink */ size = 65535; } /* now, receive data from netlink */ while (1) { unsigned char buf[size]; ret = nfnl_recv(h, buf, sizeof(buf)); if (ret == -1) { /* interrupted syscall must retry */ if (errno == EINTR) continue; break; } ret = nfnl_process(h, buf, ret); if (ret <= NFNL_CB_STOP) break; } return ret; } /** * nfnl_query - request/response communication challenge * @h: nfnetlink handler * @nlh: nfnetlink message to be sent * * This function sends a nfnetlink message to a certain subsystem and * receives the response messages associated, such messages are passed to * the callback registered via register_callback(). Note that this function * is a replacement for nfnl_talk, its use is recommended. * * On success, 0 is returned. On error, a negative is returned. If your * does not want to listen to events anymore, then your callback must * return NFNL_CB_STOP. * * Note that ENOBUFS is returned in case that nfnetlink is exhausted. In * that case is possible that the information requested is incomplete. */ int nfnl_query(struct nfnl_handle *h, struct nlmsghdr *nlh) { assert(h); assert(nlh); if (nfnl_send(h, nlh) == -1) return -1; return nfnl_catch(h); }