/*- * Copyright (c) 2004 Lev Walkin . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: loop-ipq.c,v 1.13 2004/11/12 06:51:38 vlm Exp $ */ #include "ipcad.h" #include "opt.h" #ifndef PSRC_ipq void * process_ipq(void *psp) { (void)psp; assert(!"Can't be here"); return NULL; } #else /* !PSRC_ipq */ static void _ipq_set_verdict(packet_source_t *ps, unsigned long id, unsigned int verdict); /* * This is the interface loop - a busy horse handling interface statistics. */ void * process_ipq(void *psp) { char buf[1024]; struct nlmsghdr *h = (void *)buf; packet_source_t *ps = psp; ipq_packet_msg_t *m; int ret; assert(ps->iface_type == IFACE_IPQ); assert(sizeof(buf) - sizeof(struct nlmsghdr) >= 128); for(;;) { int captured_size; int toend_size; if(signoff_now) break; if(ps->state != PST_READY || ps->fd == -1) { if(init_packet_source(ps, 1)) { sleep(5); continue; } else { assert(ps->state == PST_READY); assert(ps->fd != -1); } } ret = recvfrom(ps->fd, buf, sizeof(buf), 0, 0, 0); if(ret < 0) { int fd = ps->fd; ps->fd = -1; close(fd); sleep(1); continue; } if(ret < (int)sizeof(*h)) /* Paranoya */ continue; switch(h->nlmsg_type) { case IPQM_PACKET: m = NLMSG_DATA(h); break; default: continue; } toend_size = ret - ((char *)m->payload - (char *)buf); captured_size = m->data_len; if(toend_size < captured_size) captured_size = toend_size; process_packet_data(ps, m->payload, captured_size, 0, 0); _ipq_set_verdict(ps, m->packet_id, NF_ACCEPT); } return 0; } static void _ipq_set_verdict(packet_source_t *ps, unsigned long id, unsigned int verdict) { struct nlmsghdr nlh; ipq_peer_msg_t pm; struct msghdr msg; struct iovec iov[3]; memset(&nlh, 0, sizeof(nlh)); nlh.nlmsg_flags = NLM_F_REQUEST; nlh.nlmsg_type = IPQM_VERDICT; nlh.nlmsg_pid = ps->iface.ipq.local.nl_pid; memset(&pm, 0, sizeof(pm)); pm.msg.verdict.value = verdict; pm.msg.verdict.id = id; pm.msg.verdict.data_len = 0; iov[0].iov_base = &nlh; iov[0].iov_len = sizeof(nlh); iov[1].iov_base = ± iov[1].iov_len = sizeof(pm); nlh.nlmsg_len = sizeof(nlh) + sizeof(pm); memset(&msg, 0, sizeof(msg)); msg.msg_name = (void *)&ps->iface.ipq.peer; msg.msg_namelen = sizeof(ps->iface.ipq.peer); msg.msg_iov = iov; msg.msg_iovlen = 2; (void)sendmsg(ps->fd, &msg, 0); } #endif /* Linux IPQ/libipq(3) */