Netfilter ARP日志

定义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

### Keepalived 主备切换后地址未漂移回解决方案 当遇到 Keepalived 主备切换过程中虚拟 IP (VIP) 地址未能成功漂移回到原主节点的情况时,可以考虑以下几个方面进行排查和修复。 #### 1. 检查 VRRP 协议状态同步情况 VRRP 是实现高可用性的核心机制,在 Keepalived 中用于监控 Master 和 Backup 节点之间的通信状况。如果网络连接不稳定或存在延迟,则可能导致 VIP 不会自动迁移至新的 Master 节点上[^3]。因此建议先确认两台服务器间的连通性和响应时间是否正常,并查看日志文件 `/var/log/messages` 或者 `/var/log/syslog` 来获取更多关于 VRRP 的调试信息。 #### 2. 审核配置文件设置 确保 `keepalived.conf` 文件中的参数定义合理有效。特别是对于优先级 (`priority`)、抢占模式(`preempt`)以及通告间隔(`advert_int`)等选项要仔细校验其数值设定是否恰当。另外还需要注意检查是否有其他不合理的规则影响到了正常的 failover 流程[^1]: ```bash global_defs { router_id LVS_DEVEL } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 12345678 } unicast_peer { 192.168.1.2 } notify_master "/usr/local/bin/vip.sh" } ``` 上述示例展示了如何指定通知脚本路径以便于执行额外操作(如添加/删除路由表项),这有助于提高故障恢复的成功率。 #### 3. 排除内核参数干扰因素 有时 Linux 内核层面的一些安全特性也会阻碍 VIP 的顺利转移。比如 ARP 缓存刷新频率过低就容易造成客户端无法及时更新目标 MAC 地址从而继续访问旧网卡接口;还有就是 netfilter/ipvs 模块加载顺序不当也会影响服务稳定性。针对这些问题可以通过调整 sysctl 参数来进行优化处理: ```bash net.ipv4.ip_nonlocal_bind=1 net.ipv4.conf.all.arp_ignore=1 net.ipv4.conf.all.arp_announce=2 ``` 以上命令允许绑定本地不存在的IP地址并控制ARP请求的行为方式以减少不必要的冲突发生概率。 #### 4. 实施测试验证措施 最后一步是在生产环境中模拟一次完整的failover过程来检验所做修改的效果。具体做法是从当前正在工作的Master节点主动触发停机事件观察Backup能否迅速接管业务流量并且待前者恢复正常运作后再看VIP是否会按预期返回给它。期间密切监视系统资源消耗水平变化趋势防止因负载过高引发次生灾害。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值