/*************************************************************************** * Copyright (C) 07/2007 by Olaf Rempel * * razzor@kopf-tisch.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; version 2 of the License * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #include "configfile.h" #include "event.h" #include "logging.h" #include "ulogparse.h" static struct event_fd *nl_event; #define BUFLEN 65536 static char buf[BUFLEN]; static int netlink_cb(int fd, void *privdata) { int len = recv(fd, buf, BUFLEN, 0); if (len <= 0) { log_print(LOG_WARN, "netlink_cb(): recv()"); return 0; } struct nlmsghdr *nlh = (struct nlmsghdr *)buf; if (nlh->nlmsg_flags & MSG_TRUNC || len > BUFLEN) { log_print(LOG_WARN, "netlink_cb(): message truncated"); return 0; } if (!NLMSG_OK(nlh, BUFLEN)) { log_print(LOG_WARN, "netlink_cb(): parse error"); return 0; } while (nlh != NULL) { parse_ulog_packet(NLMSG_DATA(nlh)); if (nlh->nlmsg_flags & NLM_F_MULTI && nlh->nlmsg_type != NLMSG_DONE) { int remain_len = (len - ((char *)nlh - buf)); nlh = NLMSG_NEXT(nlh, remain_len); } else { nlh = NULL; } } return 0; } int netlink_init(void) { int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_NFLOG); if (fd == 0) { log_print(LOG_ERROR, "netlink_init(): socket()"); return -1; } struct sockaddr_nl local; local.nl_family = AF_NETLINK; local.nl_pid = 0; local.nl_groups = 0; if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) { log_print(LOG_ERROR, "netlink_init(): bind()"); close(fd); return -1; } socklen_t addrlen = sizeof(local); if (getsockname(fd, (struct sockaddr *)&local, &addrlen) < 0) { log_print(LOG_ERROR, "netlink_init(): getsockname()"); close(fd); return -1; } /* second bind with correct pid (assigned from kernel) */ local.nl_groups = config_get_int("global", "netlink_group", 1); if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) { log_print(LOG_ERROR, "netlink_init(): bind()"); close(fd); return -1; } log_print(LOG_INFO, "netlink: listening on group %d", local.nl_groups); nl_event = event_add_readfd(NULL, fd, netlink_cb, NULL); return 0; } void netlink_close(void) { int fd = event_get_fd(nl_event); event_remove_fd(nl_event); close(fd); }