| /* SPDX-License-Identifier: LGPL-2.1-only */ |
| /* |
| * src/nf-ct-events.c Listen on Conntrack Events |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation version 2.1 |
| * of the License. |
| * |
| * Copyright (c) 2018 Avast software |
| */ |
| |
| #include <netlink/cli/utils.h> |
| #include <netlink/cli/ct.h> |
| |
| #include <linux/netlink.h> |
| #include <linux/netfilter/nfnetlink.h> |
| #include <linux/netfilter/nfnetlink_conntrack.h> |
| |
| struct private_nl_object |
| { |
| int ce_refcnt; |
| struct nl_object_ops * ce_ops; |
| struct nl_cache * ce_cache; |
| struct nl_list_head ce_list; |
| int ce_msgtype; |
| int ce_flags; |
| uint64_t ce_mask; |
| }; |
| |
| static void nf_conntrack_parse_callback(struct nl_object *obj, void *opaque) |
| { |
| struct nl_dump_params params = { |
| .dp_fd = stdout, |
| .dp_type = NL_DUMP_DETAILS, |
| }; |
| |
| nl_object_dump(obj, ¶ms); |
| } |
| |
| static int nf_conntrack_event_callback(struct nl_msg *msg, void *opaque) |
| { |
| int err; |
| struct nlmsghdr *hdr = nlmsg_hdr(msg); |
| |
| enum cntl_msg_types type = (enum cntl_msg_types) NFNL_MSG_TYPE(hdr->nlmsg_type); |
| |
| int flags = hdr->nlmsg_flags; |
| |
| if (type == IPCTNL_MSG_CT_DELETE) { |
| printf("DELETE "); |
| } else if (type == IPCTNL_MSG_CT_NEW) { |
| if (flags & (NLM_F_CREATE|NLM_F_EXCL)) { |
| printf("NEW "); |
| } else { |
| printf("UPDATE "); |
| } |
| } else { |
| printf("UNKNOWN "); |
| } |
| |
| if ((err = nl_msg_parse(msg, &nf_conntrack_parse_callback, opaque)) < 0) { |
| nl_cli_fatal(err, "nl_msg_parse: %s", nl_geterror(err)); |
| } |
| /* Continue with next event */ |
| return NL_OK; |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| struct nl_sock *socket; |
| int err; |
| |
| socket = nl_cli_alloc_socket(); |
| if (socket == NULL) { |
| nl_cli_fatal(ENOBUFS, "Unable to allocate netlink socket"); |
| } |
| |
| /* |
| * Disable sequence number checking. |
| * This is required to allow messages to be processed which were not requested by |
| * a preceding request message, e.g. netlink events. |
| */ |
| nl_socket_disable_seq_check(socket); |
| |
| /* subscribe conntrack events */ |
| nl_join_groups(socket, NF_NETLINK_CONNTRACK_NEW | |
| NF_NETLINK_CONNTRACK_UPDATE | |
| NF_NETLINK_CONNTRACK_DESTROY | |
| NF_NETLINK_CONNTRACK_EXP_NEW | |
| NF_NETLINK_CONNTRACK_EXP_UPDATE | |
| NF_NETLINK_CONNTRACK_EXP_DESTROY); |
| |
| nl_cli_connect(socket, NETLINK_NETFILTER); |
| |
| nl_socket_modify_cb(socket, NL_CB_VALID, NL_CB_CUSTOM, &nf_conntrack_event_callback, 0); |
| |
| while (1) { |
| |
| errno = 0; |
| if ((err = nl_recvmsgs_default(socket)) < 0) { |
| switch (errno) { |
| case ENOBUFS: |
| // just print warning |
| fprintf(stderr, "Lost events because of ENOBUFS\n"); |
| break; |
| case EAGAIN: |
| case EINTR: |
| // continue reading |
| break; |
| default: |
| nl_cli_fatal(err, "Failed to receive: %s", nl_geterror(err)); |
| } |
| } |
| } |
| } |