定义ARP协议的日志结构nf_arp_logger,类型为NF_LOG_TYPE_LOG,处理函数为nf_log_arp_packet。目前内核支持的另一日志类型为NF_LOG_TYPE_ULOG。
static struct nf_logger nf_arp_logger __read_mostly = {
.name = "nf_log_arp",
.type = NF_LOG_TYPE_LOG,
.logfn = nf_log_arp_packet,
.me = THIS_MODULE,
};
由nf_log_register将以上日志结构添加到全局loggers数组中。对于各个命名空间,由nf_log_set将其添加到命名空间独立的nf_loggers数组中。
static int __net_init nf_log_arp_net_init(struct net *net)
{
return nf_log_set(net, NFPROTO_ARP, &nf_arp_logger);
}
static struct pernet_operations nf_log_arp_net_ops = {
.init = nf_log_arp_net_init,
.exit = nf_log_arp_net_exit,
};
static int __init nf_log_arp_init(void)
{
int ret;
ret = register_pernet_subsys(&nf_log_arp_net_ops);
if (ret < 0)
return ret;
ret = nf_log_register(NFPROTO_ARP, &nf_arp_logger);
日志处理
默认的日志类型、级别和标志位NF_LOG_DEFAULT_MASK(0xf)。
static const struct nf_loginfo default_loginfo = {
.type = NF_LOG_TYPE_LOG,
.u = {
.log = {
.level = LOGLEVEL_NOTICE,
.logflags = NF_LOG_DEFAULT_MASK,
},
},
};
默认情况下,仅记录init_net命名空间的日志信息,要记录其它的命名空间日志,需打开nf_log_all_netns开关。
# sysctl -a | grep nf_log_all_netns
net.netfilter.nf_log_all_netns = 0
#
# sysctl net.netfilter.nf_log_all_netns=1
net.netfilter.nf_log_all_netns = 1
日志处理函数中,首先分配日志缓存结构nf_log_buf。之后,打印报文的入接口和出接口信息,以及ARP协议的信息。最后,在nf_log_buf_close函数中打印缓存中的信息,释放分配的日志缓存。
static void nf_log_arp_packet(struct net *net, u_int8_t pf,
unsigned int hooknum, const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const struct nf_loginfo *loginfo,
const char *prefix)
{
struct nf_log_buf *m;
/* FIXME: Disabled from containers until syslog ns is supported */
if (!net_eq(net, &init_net) && !sysctl_nf_log_all_netns)
return;
m = nf_log_buf_open();
if (!loginfo)
loginfo = &default_loginfo;
nf_log_dump_packet_common(m, pf, hooknum, skb, in, out, loginfo, prefix);
dump_arp_packet(m, loginfo, skb, 0);
nf_log_buf_close(m);
对于ARP协议,如果报文长度小于ARP协议的头部的长度,说明报文被截断。如果设置了NF_LOG_MACDECODE,记录报文的源和目的MAC地址,以及VLAN信息和协议。
static void dump_arp_packet(struct nf_log_buf *m,
const struct nf_loginfo *info,
const struct sk_buff *skb, unsigned int nhoff)
{
const struct arppayload *ap;
struct arppayload _arpp;
const struct arphdr *ah;
struct arphdr _arph;
ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
if (ah == NULL) {
nf_log_buf_add(m, "TRUNCATED");
return;
}
if (info->type == NF_LOG_TYPE_LOG)
logflags = info->u.log.logflags;
else
logflags = NF_LOG_DEFAULT_MASK;
if (logflags & NF_LOG_MACDECODE) {
nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM ",
eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest);
nf_log_dump_vlan(m, skb);
nf_log_buf_add(m, "MACPROTO=%04x ", ntohs(eth_hdr(skb)->h_proto));
}
记录硬件地址类型(如Ethernet=1),协议地址类型(如IPv4=0x800)和操作码(如Request=1)。如果硬件地址类型等于Ethernet,并且硬件地址长度等于6,协议地址类型等于4,记录ARP协议的载荷信息。
ARP载荷信息包括发送者(sender)的MAC地址和IP地址,以及目标(target)的MAC地址和IP地址。
nf_log_buf_add(m, "ARP HTYPE=%d PTYPE=0x%04x OPCODE=%d",
ntohs(ah->ar_hrd), ntohs(ah->ar_pro), ntohs(ah->ar_op));
/* If it's for Ethernet and the lengths are OK, then log the ARP payload.
*/
if (ah->ar_hrd != htons(ARPHRD_ETHER) ||
ah->ar_hln != ETH_ALEN ||
ah->ar_pln != sizeof(__be32))
return;
ap = skb_header_pointer(skb, sizeof(_arph), sizeof(_arpp), &_arpp);
if (ap == NULL) {
nf_log_buf_add(m, " INCOMPLETE [%zu bytes]", skb->len - sizeof(_arph));
return;
}
nf_log_buf_add(m, " MACSRC=%pM IPSRC=%pI4 MACDST=%pM IPDST=%pI4",
ap->mac_src, ap->ip_src, ap->mac_dst, ap->ip_dst);
ARP日志显示
加载模块,将ARP协议(NFPROTO_ARP=3)的logger设置为nf_log_arp。
# modprobe nf_log_arp
#
# sysctl net.netfilter.nf_log.3=nf_log_arp
net.netfilter.nf_log.3 = nf_log_arp
加载的模块:
$ lsmod | grep arp
nf_log_arp 16384 0
nf_log_common 16384 2 nf_log_ipv4,nf_log_arp
nftables规则配置如下:
# nft add table arp raw
# nft add chain arp raw input { type filter hook input priority 0 \; }
# nft add rule arp raw input log
#
# nft list table arp raw
table arp raw {
chain input {
type filter hook input priority filter; policy accept;
log
}
}
查看/var/log/kern.log,其中记录的ARP报文日志,如下:
# tail -f /var/log/kern.log
Feb 13 14:39:42 advanced kernel: [ 8232.798264] IN=ens33 OUT= ARP HTYPE=1 PTYPE=0x0800 OPCODE=1 MACSRC=54:a7:03:16:55:c2 IPSRC=192.168.3.123 MACDST=00:00:00:00:00:00 IPDST=192.168.3.36
Feb 13 14:39:42 advanced kernel: [ 8232.801235] IN=ens33 OUT= ARP HTYPE=1 PTYPE=0x0800 OPCODE=1 MACSRC=54:a7:03:16:55:c2 IPSRC=192.168.3.123 MACDST=00:00:00:00:00:00 IPDST=192.168.3.1
内核版本 5.10
|