You can use the configuration file of ulogd / etc / ulogd Conf configure NFLOG related settings. See ebtables log nflog.
ulogd configuration
File input / packet / ulogd in ulogd-2.0.7_ inppkt_ NFLOG. c. Used to set the nfnetlink log configuration. First, create the communication socket interface nflog_open, the subsystem ID is specified as NFNL_SUBSYS_ULOG.
static int start(struct ulogd_pluginstance *upi) { struct nflog_input *ui = (struct nflog_input *) upi->private; ulogd_log(ULOGD_DEBUG, "opening nfnetlink socket\n"); ui->nful_h = nflog_open();
Set the protocol type of listening, as follows:_ INET,AF_INET6, and AF_BRIDGE. Corresponding to NFULNL_CFG_CMD_PF_BIND command.
/* This is the system logging (conntrack, ...) facility */ if ((group_ce(upi->config_kset).u.value == 0) || (bind_ce(upi->config_kset).u.value > 0)) { if (become_system_logging(upi, AF_INET) == -1) goto out_handle; if (become_system_logging(upi, AF_INET6) == -1) goto out_handle; if (become_system_logging(upi, AF_BRIDGE) == -1) goto out_handle; }
Bind the configured netlink group, corresponding to the command NFULNL_CFG_CMD_BIND.
ulogd_log(ULOGD_DEBUG, "binding to log group %d\n", group_ce(upi->config_kset).u.value); ui->nful_gh = nflog_bind_group(ui->nful_h, group_ce(upi->config_kset).u.value);
Configure nfulnl_ COPY_ Pack mode, corresponding to the command NFULNL_MSG_CONFIG.
nflog_set_mode(ui->nful_gh, NFULNL_COPY_PACKET, 0xffff);
ulogd sets the size of the receive cache, using SO_RCVBUFFORCE/SO_RCVBUF does not use libnetfilter_ Nfulnl provided in the log Library_ MSG_ netlink attribute nfula of config command_ CFG_ NLBUFSIZ.
if (nlsockbufsize_ce(upi->config_kset).u.value) { setnlbufsiz(upi, nlsockbufsize_ce(upi->config_kset).u.value);
By command nfulnl_ MSG_ Attribute nfula in config_ CFG_ Qthresh sets the queue threshold.
if (nlthreshold_ce(upi->config_kset).u.value) { if (nflog_set_qthresh(ui->nful_gh, nlthreshold_ce(upi->config_kset).u.value) >= 0) ulogd_log(ULOGD_NOTICE, "NFLOG netlink queue threshold has been set to %d\n", nlthreshold_ce(upi->config_kset).u.value); }
By command nfulnl_ MSG_ Attribute nfula in config_ CFG_ Timeout sets the kernel log sending timer.
if (nltimeout_ce(upi->config_kset).u.value) { if (nflog_set_timeout(ui->nful_gh, nltimeout_ce(upi->config_kset).u.value) >= 0) ulogd_log(ULOGD_NOTICE, "NFLOG netlink queue timeout has " "been set to %d\n", nltimeout_ce(upi->config_kset).u.value); }
By command nfulnl_ MSG_ Attribute nfula in config_ CFG_ Flags set flag bit NFULNL_CFG_F_SEQ/NFULNL_CFG_F_SEQ_GLOBAL.
/* set log flags based on configuration */ flags = 0; if (seq_ce(upi->config_kset).u.value != 0) flags = NFULNL_CFG_F_SEQ; if (seq_ce(upi->config_kset).u.value != 0) flags |= NFULNL_CFG_F_SEQ_GLOBAL; if (flags) { if (nflog_set_flags(ui->nful_gh, flags) < 0) ulogd_log(ULOGD_ERROR, "unable to set flags 0x%x\n", flags); }
Except for the configuration of receiving cache, other configurations are made by calling libnetfilter_ The functions in the log library are implemented.
Kernel processing
Register the following nfnetlink subsystem nfulnl_subsys, subsystem ID is NFNL_SUBSYS_ULOG. This ID value was specified in the previous section ulogd when creating the socket.
static const struct nfnetlink_subsystem nfulnl_subsys = { .name = "log", .subsys_id = NFNL_SUBSYS_ULOG, .cb_count = NFULNL_MSG_MAX, .cb = nfulnl_cb, }; static int __init nfnetlink_log_init(void) { status = nfnetlink_subsys_register(&nfulnl_subsys);
Register two (NFULNL_MSG_MAX) callback functions as follows, where nfulnl_ MSG_ The package processing function is null.
static const struct nfnl_callback nfulnl_cb[NFULNL_MSG_MAX] = { [NFULNL_MSG_PACKET] = { .call = nfulnl_recv_unsupp, .attr_count = NFULA_MAX, }, [NFULNL_MSG_CONFIG] = { .call = nfulnl_recv_config, .attr_count = NFULA_CFG_MAX, .policy = nfula_cfg_policy }, };
The following kernel configuration processing functions. First, parse the command word for NFULNL_CFG_CMD_PF_BIND protocol binding command with function nf_log_bind_pf processing, set the protocol record of the logger in the namespace to nfulnl_logger (name nfnetlink_log). The binding relationship can be observed through the sysctl command. Arrays 2, 7 and 10 correspond to nfproto respectively_ IPV4,NFPROTO_BRIDGE and NFPROTO_IPV6.
# sysctl -a | grep nf_log net.netfilter.nf_log.0 = NONE net.netfilter.nf_log.1 = NONE net.netfilter.nf_log.10 = nfnetlink_log net.netfilter.nf_log.11 = NONE net.netfilter.nf_log.12 = NONE net.netfilter.nf_log.2 = nfnetlink_log net.netfilter.nf_log.3 = NONE net.netfilter.nf_log.4 = NONE net.netfilter.nf_log.5 = NONE net.netfilter.nf_log.6 = NONE net.netfilter.nf_log.7 = nfnetlink_log net.netfilter.nf_log.8 = NONE net.netfilter.nf_log.9 = NONE
In addition, the netlink group configuration is not distributed through attributes, but is located in the member res of the nfgenmsg structure_ ID, take it out first.
static int nfulnl_recv_config(struct net *net, struct sock *ctnl, struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const nfula[], struct netlink_ext_ack *extack) { struct nfgenmsg *nfmsg = nlmsg_data(nlh); u_int16_t group_num = ntohs(nfmsg->res_id); struct nfulnl_instance *inst; struct nfulnl_msg_config_cmd *cmd = NULL; struct nfnl_log_net *log = nfnl_log_pernet(net); if (nfula[NFULA_CFG_CMD]) { u_int8_t pf = nfmsg->nfgen_family; cmd = nla_data(nfula[NFULA_CFG_CMD]); /* Commands without queue context */ switch (cmd->command) { case NFULNL_CFG_CMD_PF_BIND: return nf_log_bind_pf(net, pf, &nfulnl_logger); case NFULNL_CFG_CMD_PF_UNBIND: nf_log_unbind_pf(net, pf); return 0; } }
If the instance corresponding to the group already exists, but the portid s are different, it indicates that it is a different socket interface, and an error is returned.
inst = instance_lookup_get(log, group_num); if (inst && inst->peer_portid != NETLINK_CB(skb).portid) { ret = -EPERM; goto out_put; }
If the naming is not protocol binding or unbinding, continue to process other commands. For NFULNL_CFG_CMD_BIND. If the instance does not exist, the function instance_create.
if (cmd != NULL) { switch (cmd->command) { case NFULNL_CFG_CMD_BIND: if (inst) { ret = -EBUSY; goto out_put; } inst = instance_create(net, group_num, NETLINK_CB(skb).portid, sk_user_ns(NETLINK_CB(skb).sk)); break; case NFULNL_CFG_CMD_UNBIND: if (!inst) { ret = -ENODEV; goto out; } instance_destroy(log, inst); goto out_put; default: ret = -ENOTSUPP; goto out_put; }
As follows, set the mode, timeout, cache / queue size and flag bit respectively according to the attribute fields.
if (nfula[NFULA_CFG_MODE]) { struct nfulnl_msg_config_mode *params = nla_data(nfula[NFULA_CFG_MODE]); nfulnl_set_mode(inst, params->copy_mode, ntohl(params->copy_range)); } if (nfula[NFULA_CFG_TIMEOUT]) { __be32 timeout = nla_get_be32(nfula[NFULA_CFG_TIMEOUT]); nfulnl_set_timeout(inst, ntohl(timeout)); } if (nfula[NFULA_CFG_NLBUFSIZ]) { __be32 nlbufsiz = nla_get_be32(nfula[NFULA_CFG_NLBUFSIZ]); nfulnl_set_nlbufsiz(inst, ntohl(nlbufsiz)); } if (nfula[NFULA_CFG_QTHRESH]) { __be32 qthresh = nla_get_be32(nfula[NFULA_CFG_QTHRESH]); nfulnl_set_qthresh(inst, ntohl(qthresh)); } if (nfula[NFULA_CFG_FLAGS]) nfulnl_set_flags(inst, flags);
Kernel instance creation
If the instance corresponding to the group does not exist, assign a new instance.
static struct nfulnl_instance * instance_create(struct net *net, u_int16_t group_num, u32 portid, struct user_namespace *user_ns) { struct nfulnl_instance *inst; struct nfnl_log_net *log = nfnl_log_pernet(net); spin_lock_bh(&log->instances_lock); if (__instance_lookup(log, group_num)) { err = -EEXIST; goto out_unlock; } inst = kzalloc(sizeof(*inst), GFP_ATOMIC); INIT_HLIST_NODE(&inst->hlist); spin_lock_init(&inst->lock); /* needs to be two, since we _put() after creation */ refcount_set(&inst->use, 2);
Set the initial value for the instance and link the instance to the instance linked list of the namespace.
timer_setup(&inst->timer, nfulnl_timer, 0); inst->net = get_net(net); inst->peer_user_ns = user_ns; inst->peer_portid = portid; inst->group_num = group_num; inst->qthreshold = NFULNL_QTHRESH_DEFAULT; inst->flushtimeout = NFULNL_TIMEOUT_DEFAULT; inst->nlbufsiz = NFULNL_NLBUFSIZ_DEFAULT; inst->copy_mode = NFULNL_COPY_PACKET; inst->copy_range = NFULNL_COPY_RANGE_MAX; hlist_add_head_rcu(&inst->hlist, &log->instance_table[instance_hashfn(group_num)]);
The timer of the instance is initialized above. When the queue length exceeds the defined length (NFULNL_QTHRESH_DEFAULT) or the timer expires, the cache message of the instance will be sent.
static void nfulnl_timer(struct timer_list *t) { struct nfulnl_instance *inst = from_timer(inst, t, timer); spin_lock_bh(&inst->lock); if (inst->skb) __nfulnl_send(inst);
If the cached skb in the instance is composed of multiple message data, add NLMSG_DONE indicates the end.
static void __nfulnl_send(struct nfulnl_instance *inst) { if (inst->qlen > 1) { struct nlmsghdr *nlh = nlmsg_put(inst->skb, 0, 0, NLMSG_DONE, sizeof(struct nfgenmsg), 0); if (WARN_ONCE(!nlh, "bad nlskb size: %u, tailroom %d\n", inst->skb->len, skb_tailroom(inst->skb))) { kfree_skb(inst->skb); goto out; } } nfnetlink_unicast(inst->skb, inst->net, inst->peer_portid);
Mode setting
Set copy mode for NFULNL_COPY_PACKET: set the length of copied message data.
static int nfulnl_set_mode(struct nfulnl_instance *inst, u_int8_t mode, unsigned int range) { switch (mode) { case NFULNL_COPY_NONE: case NFULNL_COPY_META: inst->copy_mode = mode; inst->copy_range = 0; break; case NFULNL_COPY_PACKET: inst->copy_mode = mode; if (range == 0) range = NFULNL_COPY_RANGE_MAX; inst->copy_range = min_t(unsigned int, range, NFULNL_COPY_RANGE_MAX);
Other settings
Set the flush timeout of the instance. As above, the default is 100s (NFULNL_TIMEOUT_DEFAULT).
static void nfulnl_set_timeout(struct nfulnl_instance *inst, u_int32_t timeout) { spin_lock_bh(&inst->lock); inst->flushtimeout = timeout;
In function nfulnl_ log_ In packet, when starting the timer, the timing duration is set to 1 second by default.
if (inst->qlen >= qthreshold) __nfulnl_flush(inst); /* timer_pending always called within inst->lock, so there * is no chance of a race here */ else if (!timer_pending(&inst->timer)) { instance_get(inst); inst->timer.expires = jiffies + (inst->flushtimeout*HZ/100); add_timer(&inst->timer); }
Set the queue length and flag bit of the instance.
static void nfulnl_set_qthresh(struct nfulnl_instance *inst, u_int32_t qthresh) { spin_lock_bh(&inst->lock); inst->qthreshold = qthresh; spin_unlock_bh(&inst->lock); } static int nfulnl_set_flags(struct nfulnl_instance *inst, u_int16_t flags) { spin_lock_bh(&inst->lock); inst->flags = flags;
Kernel version 5.10