Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: ipt_LOG/ip6t_LOG: add option to print decoded MAC header

The LOG targets print the entire MAC header as one long string, which is not
readable very well:

IN=eth0 OUT= MAC=00:15:f2:24:91:f8:00:1b:24:dc:61:e6:08:00 ...

Add an option to decode known header formats (currently just ARPHRD_ETHER devices)
in their individual fields:

IN=eth0 OUT= MACSRC=00:1b:24:dc:61:e6 MACDST=00:15:f2:24:91:f8 MACPROTO=0800 ...
IN=eth0 OUT= MACSRC=00:1b:24:dc:61:e6 MACDST=00:15:f2:24:91:f8 MACPROTO=86dd ...

The option needs to be explicitly enabled by userspace to avoid breaking
existing parsers.

Signed-off-by: Patrick McHardy <kaber@trash.net>

+97 -44
+2 -1
include/linux/netfilter_ipv4/ipt_LOG.h
··· 7 7 #define IPT_LOG_IPOPT 0x04 /* Log IP options */ 8 8 #define IPT_LOG_UID 0x08 /* Log UID owning local socket */ 9 9 #define IPT_LOG_NFLOG 0x10 /* Unsupported, don't reuse */ 10 - #define IPT_LOG_MASK 0x1f 10 + #define IPT_LOG_MACDECODE 0x20 /* Decode MAC header */ 11 + #define IPT_LOG_MASK 0x2f 11 12 12 13 struct ipt_log_info { 13 14 unsigned char level;
+2 -1
include/linux/netfilter_ipv6/ip6t_LOG.h
··· 7 7 #define IP6T_LOG_IPOPT 0x04 /* Log IP options */ 8 8 #define IP6T_LOG_UID 0x08 /* Log UID owning local socket */ 9 9 #define IP6T_LOG_NFLOG 0x10 /* Unsupported, don't use */ 10 - #define IP6T_LOG_MASK 0x1f 10 + #define IP6T_LOG_MACDECODE 0x20 /* Decode MAC header */ 11 + #define IP6T_LOG_MASK 0x2f 11 12 12 13 struct ip6t_log_info { 13 14 unsigned char level;
+40 -14
net/ipv4/netfilter/ipt_LOG.c
··· 13 13 #include <linux/module.h> 14 14 #include <linux/spinlock.h> 15 15 #include <linux/skbuff.h> 16 + #include <linux/if_arp.h> 16 17 #include <linux/ip.h> 17 18 #include <net/icmp.h> 18 19 #include <net/udp.h> ··· 364 363 /* maxlen = 230+ 91 + 230 + 252 = 803 */ 365 364 } 366 365 366 + static void dump_mac_header(const struct nf_loginfo *info, 367 + const struct sk_buff *skb) 368 + { 369 + struct net_device *dev = skb->dev; 370 + unsigned int logflags = 0; 371 + 372 + if (info->type == NF_LOG_TYPE_LOG) 373 + logflags = info->u.log.logflags; 374 + 375 + if (!(logflags & IPT_LOG_MACDECODE)) 376 + goto fallback; 377 + 378 + switch (dev->type) { 379 + case ARPHRD_ETHER: 380 + printk("MACSRC=%pM MACDST=%pM MACPROTO=%04x ", 381 + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, 382 + ntohs(eth_hdr(skb)->h_proto)); 383 + return; 384 + default: 385 + break; 386 + } 387 + 388 + fallback: 389 + printk("MAC="); 390 + if (dev->hard_header_len && 391 + skb->mac_header != skb->network_header) { 392 + const unsigned char *p = skb_mac_header(skb); 393 + unsigned int i; 394 + 395 + printk("%02x", *p++); 396 + for (i = 1; i < dev->hard_header_len; i++, p++) 397 + printk(":%02x", *p); 398 + } 399 + printk(" "); 400 + } 401 + 367 402 static struct nf_loginfo default_loginfo = { 368 403 .type = NF_LOG_TYPE_LOG, 369 404 .u = { ··· 441 404 } 442 405 #endif 443 406 444 - if (in && !out) { 445 - /* MAC logging for input chain only. */ 446 - printk("MAC="); 447 - if (skb->dev && skb->dev->hard_header_len && 448 - skb->mac_header != skb->network_header) { 449 - int i; 450 - const unsigned char *p = skb_mac_header(skb); 451 - 452 - printk("%02x", *p++); 453 - for (i = 1; i < skb->dev->hard_header_len; i++, p++) 454 - printk(":%02x", *p); 455 - } 456 - printk(" "); 457 - } 407 + /* MAC logging for input path only. */ 408 + if (in && !out) 409 + dump_mac_header(loginfo, skb); 458 410 459 411 dump_packet(loginfo, skb, 0); 460 412 printk("\n");
+53 -28
net/ipv6/netfilter/ip6t_LOG.c
··· 373 373 printk("MARK=0x%x ", skb->mark); 374 374 } 375 375 376 + static void dump_mac_header(const struct nf_loginfo *info, 377 + const struct sk_buff *skb) 378 + { 379 + struct net_device *dev = skb->dev; 380 + unsigned int logflags = 0; 381 + 382 + if (info->type == NF_LOG_TYPE_LOG) 383 + logflags = info->u.log.logflags; 384 + 385 + if (!(logflags & IP6T_LOG_MACDECODE)) 386 + goto fallback; 387 + 388 + switch (dev->type) { 389 + case ARPHRD_ETHER: 390 + printk("MACSRC=%pM MACDST=%pM MACPROTO=%04x ", 391 + eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, 392 + ntohs(eth_hdr(skb)->h_proto)); 393 + return; 394 + default: 395 + break; 396 + } 397 + 398 + fallback: 399 + printk("MAC="); 400 + if (dev->hard_header_len && 401 + skb->mac_header != skb->network_header) { 402 + const unsigned char *p = skb_mac_header(skb); 403 + unsigned int len = dev->hard_header_len; 404 + unsigned int i; 405 + 406 + if (dev->type == ARPHRD_SIT && 407 + (p -= ETH_HLEN) < skb->head) 408 + p = NULL; 409 + 410 + if (p != NULL) { 411 + printk("%02x", *p++); 412 + for (i = 1; i < len; i++) 413 + printk(":%02x", p[i]); 414 + } 415 + printk(" "); 416 + 417 + if (dev->type == ARPHRD_SIT) { 418 + const struct iphdr *iph = 419 + (struct iphdr *)skb_mac_header(skb); 420 + printk("TUNNEL=%pI4->%pI4 ", &iph->saddr, &iph->daddr); 421 + } 422 + } else 423 + printk(" "); 424 + } 425 + 376 426 static struct nf_loginfo default_loginfo = { 377 427 .type = NF_LOG_TYPE_LOG, 378 428 .u = { ··· 450 400 prefix, 451 401 in ? in->name : "", 452 402 out ? out->name : ""); 453 - if (in && !out) { 454 - unsigned int len; 455 - /* MAC logging for input chain only. */ 456 - printk("MAC="); 457 - if (skb->dev && (len = skb->dev->hard_header_len) && 458 - skb->mac_header != skb->network_header) { 459 - const unsigned char *p = skb_mac_header(skb); 460 - int i; 461 403 462 - if (skb->dev->type == ARPHRD_SIT && 463 - (p -= ETH_HLEN) < skb->head) 464 - p = NULL; 465 - 466 - if (p != NULL) { 467 - printk("%02x", *p++); 468 - for (i = 1; i < len; i++) 469 - printk(":%02x", p[i]); 470 - } 471 - printk(" "); 472 - 473 - if (skb->dev->type == ARPHRD_SIT) { 474 - const struct iphdr *iph = 475 - (struct iphdr *)skb_mac_header(skb); 476 - printk("TUNNEL=%pI4->%pI4 ", 477 - &iph->saddr, &iph->daddr); 478 - } 479 - } else 480 - printk(" "); 481 - } 404 + /* MAC logging for input path only. */ 405 + if (in && !out) 406 + dump_mac_header(loginfo, skb); 482 407 483 408 dump_packet(loginfo, skb, skb_network_offset(skb), 1); 484 409 printk("\n");