0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/module.h>
0013 #include <linux/ip.h>
0014 #include <linux/in.h>
0015 #include <linux/if_arp.h>
0016 #include <linux/spinlock.h>
0017 #include <net/netfilter/nf_log.h>
0018 #include <linux/ipv6.h>
0019 #include <net/ipv6.h>
0020 #include <linux/in6.h>
0021 #include <linux/netfilter/x_tables.h>
0022 #include <linux/netfilter_bridge/ebtables.h>
0023 #include <linux/netfilter_bridge/ebt_log.h>
0024 #include <linux/netfilter.h>
0025
0026 static DEFINE_SPINLOCK(ebt_log_lock);
0027
0028 static int ebt_log_tg_check(const struct xt_tgchk_param *par)
0029 {
0030 struct ebt_log_info *info = par->targinfo;
0031
0032 if (info->bitmask & ~EBT_LOG_MASK)
0033 return -EINVAL;
0034 if (info->loglevel >= 8)
0035 return -EINVAL;
0036 info->prefix[EBT_LOG_PREFIX_SIZE - 1] = '\0';
0037 return 0;
0038 }
0039
0040 struct tcpudphdr {
0041 __be16 src;
0042 __be16 dst;
0043 };
0044
0045 struct arppayload {
0046 unsigned char mac_src[ETH_ALEN];
0047 unsigned char ip_src[4];
0048 unsigned char mac_dst[ETH_ALEN];
0049 unsigned char ip_dst[4];
0050 };
0051
0052 static void
0053 print_ports(const struct sk_buff *skb, uint8_t protocol, int offset)
0054 {
0055 if (protocol == IPPROTO_TCP ||
0056 protocol == IPPROTO_UDP ||
0057 protocol == IPPROTO_UDPLITE ||
0058 protocol == IPPROTO_SCTP ||
0059 protocol == IPPROTO_DCCP) {
0060 const struct tcpudphdr *pptr;
0061 struct tcpudphdr _ports;
0062
0063 pptr = skb_header_pointer(skb, offset,
0064 sizeof(_ports), &_ports);
0065 if (pptr == NULL) {
0066 pr_cont(" INCOMPLETE TCP/UDP header");
0067 return;
0068 }
0069 pr_cont(" SPT=%u DPT=%u", ntohs(pptr->src), ntohs(pptr->dst));
0070 }
0071 }
0072
0073 static void
0074 ebt_log_packet(struct net *net, u_int8_t pf, unsigned int hooknum,
0075 const struct sk_buff *skb, const struct net_device *in,
0076 const struct net_device *out, const struct nf_loginfo *loginfo,
0077 const char *prefix)
0078 {
0079 unsigned int bitmask;
0080
0081
0082 if (!net_eq(net, &init_net) && !sysctl_nf_log_all_netns)
0083 return;
0084
0085 spin_lock_bh(&ebt_log_lock);
0086 printk(KERN_SOH "%c%s IN=%s OUT=%s MAC source = %pM MAC dest = %pM proto = 0x%04x",
0087 '0' + loginfo->u.log.level, prefix,
0088 in ? in->name : "", out ? out->name : "",
0089 eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
0090 ntohs(eth_hdr(skb)->h_proto));
0091
0092 if (loginfo->type == NF_LOG_TYPE_LOG)
0093 bitmask = loginfo->u.log.logflags;
0094 else
0095 bitmask = NF_LOG_DEFAULT_MASK;
0096
0097 if ((bitmask & EBT_LOG_IP) && eth_hdr(skb)->h_proto ==
0098 htons(ETH_P_IP)) {
0099 const struct iphdr *ih;
0100 struct iphdr _iph;
0101
0102 ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
0103 if (ih == NULL) {
0104 pr_cont(" INCOMPLETE IP header");
0105 goto out;
0106 }
0107 pr_cont(" IP SRC=%pI4 IP DST=%pI4, IP tos=0x%02X, IP proto=%d",
0108 &ih->saddr, &ih->daddr, ih->tos, ih->protocol);
0109 print_ports(skb, ih->protocol, ih->ihl*4);
0110 goto out;
0111 }
0112
0113 #if IS_ENABLED(CONFIG_BRIDGE_EBT_IP6)
0114 if ((bitmask & EBT_LOG_IP6) && eth_hdr(skb)->h_proto ==
0115 htons(ETH_P_IPV6)) {
0116 const struct ipv6hdr *ih;
0117 struct ipv6hdr _iph;
0118 uint8_t nexthdr;
0119 __be16 frag_off;
0120 int offset_ph;
0121
0122 ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
0123 if (ih == NULL) {
0124 pr_cont(" INCOMPLETE IPv6 header");
0125 goto out;
0126 }
0127 pr_cont(" IPv6 SRC=%pI6 IPv6 DST=%pI6, IPv6 priority=0x%01X, Next Header=%d",
0128 &ih->saddr, &ih->daddr, ih->priority, ih->nexthdr);
0129 nexthdr = ih->nexthdr;
0130 offset_ph = ipv6_skip_exthdr(skb, sizeof(_iph), &nexthdr, &frag_off);
0131 if (offset_ph == -1)
0132 goto out;
0133 print_ports(skb, nexthdr, offset_ph);
0134 goto out;
0135 }
0136 #endif
0137
0138 if ((bitmask & EBT_LOG_ARP) &&
0139 ((eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) ||
0140 (eth_hdr(skb)->h_proto == htons(ETH_P_RARP)))) {
0141 const struct arphdr *ah;
0142 struct arphdr _arph;
0143
0144 ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
0145 if (ah == NULL) {
0146 pr_cont(" INCOMPLETE ARP header");
0147 goto out;
0148 }
0149 pr_cont(" ARP HTYPE=%d, PTYPE=0x%04x, OPCODE=%d",
0150 ntohs(ah->ar_hrd), ntohs(ah->ar_pro),
0151 ntohs(ah->ar_op));
0152
0153
0154
0155
0156 if (ah->ar_hrd == htons(1) &&
0157 ah->ar_hln == ETH_ALEN &&
0158 ah->ar_pln == sizeof(__be32)) {
0159 const struct arppayload *ap;
0160 struct arppayload _arpp;
0161
0162 ap = skb_header_pointer(skb, sizeof(_arph),
0163 sizeof(_arpp), &_arpp);
0164 if (ap == NULL) {
0165 pr_cont(" INCOMPLETE ARP payload");
0166 goto out;
0167 }
0168 pr_cont(" ARP MAC SRC=%pM ARP IP SRC=%pI4 ARP MAC DST=%pM ARP IP DST=%pI4",
0169 ap->mac_src, ap->ip_src,
0170 ap->mac_dst, ap->ip_dst);
0171 }
0172 }
0173 out:
0174 pr_cont("\n");
0175 spin_unlock_bh(&ebt_log_lock);
0176 }
0177
0178 static unsigned int
0179 ebt_log_tg(struct sk_buff *skb, const struct xt_action_param *par)
0180 {
0181 const struct ebt_log_info *info = par->targinfo;
0182 struct nf_loginfo li;
0183 struct net *net = xt_net(par);
0184
0185 li.type = NF_LOG_TYPE_LOG;
0186 li.u.log.level = info->loglevel;
0187 li.u.log.logflags = info->bitmask;
0188
0189
0190
0191
0192
0193 if (info->bitmask & EBT_LOG_NFLOG)
0194 nf_log_packet(net, NFPROTO_BRIDGE, xt_hooknum(par), skb,
0195 xt_in(par), xt_out(par), &li, "%s",
0196 info->prefix);
0197 else
0198 ebt_log_packet(net, NFPROTO_BRIDGE, xt_hooknum(par), skb,
0199 xt_in(par), xt_out(par), &li, info->prefix);
0200 return EBT_CONTINUE;
0201 }
0202
0203 static struct xt_target ebt_log_tg_reg __read_mostly = {
0204 .name = "log",
0205 .revision = 0,
0206 .family = NFPROTO_BRIDGE,
0207 .target = ebt_log_tg,
0208 .checkentry = ebt_log_tg_check,
0209 .targetsize = sizeof(struct ebt_log_info),
0210 .me = THIS_MODULE,
0211 };
0212
0213 static int __init ebt_log_init(void)
0214 {
0215 return xt_register_target(&ebt_log_tg_reg);
0216 }
0217
0218 static void __exit ebt_log_fini(void)
0219 {
0220 xt_unregister_target(&ebt_log_tg_reg);
0221 }
0222
0223 module_init(ebt_log_init);
0224 module_exit(ebt_log_fini);
0225 MODULE_DESCRIPTION("Ebtables: Packet logging to syslog");
0226 MODULE_LICENSE("GPL");