/*- * 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: psrc-ipq.c,v 1.9 2004/09/01 08:21:05 vlm Exp $ */ #include "ipcad.h" #include "opt.h" #include "cfgvar.h" #include #ifndef PSRC_ipq int init_packet_source_ipq(packet_source_t *ps, int retry_mode) { (void)ps; (void)retry_mode; fprintf(stderr, "Linux IPQ source support " "is not properly compiled in " "or not supported by the target OS, " "please contact the ipcad vendor.\n"); errno = EINVAL; return -1; } #else /* PSRC_ipq */ static int _ipq_set_mode(packet_source_t *ps, int mode); int init_packet_source_ipq(packet_source_t *ps, int retry_mode) { int ipq_fd; int ret; assert(ps->state != PST_INVALID); /* Embryonic or Ready */ assert(ps->iface_type == IFACE_IPQ); /* Don't cooc crap */ /* * Obtain IPQ file descriptor. */ ipq_fd = ps->fd; if(ipq_fd == -1) { ipq_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_FIREWALL); if(ipq_fd == -1) return -1; ps->fd = ipq_fd; } else { ps->state = PST_EMBRYONIC; } memset(&ps->iface.ipq.local, 0, sizeof(ps->iface.ipq.local)); ps->iface.ipq.local.nl_family = AF_NETLINK; ps->iface.ipq.local.nl_pid = getpid(); ret = bind(ps->fd, (struct sockaddr *)&ps->iface.ipq.local, sizeof(ps->iface.ipq.local)); if(ret == -1) { ps->fd = -1; close(ipq_fd); return -1; } if(_ipq_set_mode(ps, IPQ_COPY_PACKET) == -1) { ps->fd = -1; close(ipq_fd); return -1; } /* * IPQ interface has really convoluted binding * scheme, requiring the getpid(). IPCAD is a * threaded application, so under Linux pid may change. * Defer everything until we're running inside the worker thread. */ if(!retry_mode) { ps->fd = -1; close(ipq_fd); errno = ENETDOWN; return -1; } ps->dlt = DLT_RAW; /* * Finish initialization of the structure. */ ps->state = PST_READY; return 0; } static int _ipq_set_mode(packet_source_t *ps, int mode) { struct { struct nlmsghdr nlh; ipq_peer_msg_t pm; } req; struct sockaddr_nl peer; memset(&req, 0, sizeof(req)); req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(req)); req.nlh.nlmsg_flags = NLM_F_REQUEST; req.nlh.nlmsg_type = IPQM_MODE; req.nlh.nlmsg_pid = ps->iface.ipq.local.nl_pid; req.pm.msg.mode.value = mode; req.pm.msg.mode.range = 128; memset(&peer, 0, sizeof(peer)); peer.nl_family = AF_NETLINK; return sendto(ps->fd, &req, req.nlh.nlmsg_len, 0, (struct sockaddr *)&peer, sizeof(peer)); } void print_stats_ipq(FILE *f, packet_source_t *ps) { assert(ps->iface_type == IFACE_IPQ); fprintf(f, "Interface %s: received ??", IFNameBySource(ps)); fprintf(f, ", %.0f m average %lld bytes/sec, %lld pkts/sec", ps->avg_period / 60, ps->bps_lp, ps->pps_lp ); fprintf(f, ", dropped ??"); fprintf(f, "\n"); } #endif /* !PSRC_ipq */