Commit | Line | Data |
---|---|---|
35b93951 PNA |
1 | /* |
2 | * (C) 2014 by Pablo Neira Ayuso <pablo@netfilter.org> | |
3 | * | |
4 | * Based on code from ebt_log from: | |
5 | * | |
6 | * Bart De Schuymer <bdschuym@pandora.be> | |
7 | * Harald Welte <laforge@netfilter.org> | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License version 2 as | |
11 | * published by the Free Software Foundation. | |
12 | */ | |
a81b2ce8 | 13 | |
8ac2bde2 | 14 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
35b93951 | 15 | |
a81b2ce8 | 16 | #include <linux/kernel.h> |
35b93951 PNA |
17 | #include <linux/module.h> |
18 | #include <linux/spinlock.h> | |
19 | #include <linux/skbuff.h> | |
20 | #include <linux/if_arp.h> | |
21 | #include <linux/ip.h> | |
22 | #include <net/route.h> | |
23 | ||
24 | #include <linux/netfilter.h> | |
25 | #include <linux/netfilter/xt_LOG.h> | |
26 | #include <net/netfilter/nf_log.h> | |
27 | ||
28 | static struct nf_loginfo default_loginfo = { | |
29 | .type = NF_LOG_TYPE_LOG, | |
30 | .u = { | |
31 | .log = { | |
a81b2ce8 | 32 | .level = LOGLEVEL_NOTICE, |
35b93951 PNA |
33 | .logflags = NF_LOG_MASK, |
34 | }, | |
35 | }, | |
36 | }; | |
37 | ||
38 | struct arppayload { | |
39 | unsigned char mac_src[ETH_ALEN]; | |
40 | unsigned char ip_src[4]; | |
41 | unsigned char mac_dst[ETH_ALEN]; | |
42 | unsigned char ip_dst[4]; | |
43 | }; | |
44 | ||
45 | static void dump_arp_packet(struct nf_log_buf *m, | |
46 | const struct nf_loginfo *info, | |
47 | const struct sk_buff *skb, unsigned int nhoff) | |
48 | { | |
49 | const struct arphdr *ah; | |
50 | struct arphdr _arph; | |
51 | const struct arppayload *ap; | |
52 | struct arppayload _arpp; | |
53 | ||
54 | ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph); | |
55 | if (ah == NULL) { | |
56 | nf_log_buf_add(m, "TRUNCATED"); | |
57 | return; | |
58 | } | |
59 | nf_log_buf_add(m, "ARP HTYPE=%d PTYPE=0x%04x OPCODE=%d", | |
60 | ntohs(ah->ar_hrd), ntohs(ah->ar_pro), ntohs(ah->ar_op)); | |
61 | ||
62 | /* If it's for Ethernet and the lengths are OK, then log the ARP | |
63 | * payload. | |
64 | */ | |
65 | if (ah->ar_hrd != htons(1) || | |
66 | ah->ar_hln != ETH_ALEN || | |
67 | ah->ar_pln != sizeof(__be32)) | |
68 | return; | |
69 | ||
70 | ap = skb_header_pointer(skb, sizeof(_arph), sizeof(_arpp), &_arpp); | |
71 | if (ap == NULL) { | |
72 | nf_log_buf_add(m, " INCOMPLETE [%Zu bytes]", | |
73 | skb->len - sizeof(_arph)); | |
74 | return; | |
75 | } | |
76 | nf_log_buf_add(m, " MACSRC=%pM IPSRC=%pI4 MACDST=%pM IPDST=%pI4", | |
77 | ap->mac_src, ap->ip_src, ap->mac_dst, ap->ip_dst); | |
78 | } | |
79 | ||
56768644 FW |
80 | static void nf_log_arp_packet(struct net *net, u_int8_t pf, |
81 | unsigned int hooknum, const struct sk_buff *skb, | |
82 | const struct net_device *in, | |
83 | const struct net_device *out, | |
84 | const struct nf_loginfo *loginfo, | |
85 | const char *prefix) | |
35b93951 PNA |
86 | { |
87 | struct nf_log_buf *m; | |
88 | ||
89 | /* FIXME: Disabled from containers until syslog ns is supported */ | |
90 | if (!net_eq(net, &init_net)) | |
91 | return; | |
92 | ||
93 | m = nf_log_buf_open(); | |
94 | ||
95 | if (!loginfo) | |
96 | loginfo = &default_loginfo; | |
97 | ||
98 | nf_log_dump_packet_common(m, pf, hooknum, skb, in, out, loginfo, | |
99 | prefix); | |
100 | dump_arp_packet(m, loginfo, skb, 0); | |
101 | ||
102 | nf_log_buf_close(m); | |
103 | } | |
104 | ||
105 | static struct nf_logger nf_arp_logger __read_mostly = { | |
106 | .name = "nf_log_arp", | |
107 | .type = NF_LOG_TYPE_LOG, | |
108 | .logfn = nf_log_arp_packet, | |
109 | .me = THIS_MODULE, | |
110 | }; | |
111 | ||
112 | static int __net_init nf_log_arp_net_init(struct net *net) | |
113 | { | |
114 | nf_log_set(net, NFPROTO_ARP, &nf_arp_logger); | |
115 | return 0; | |
116 | } | |
117 | ||
118 | static void __net_exit nf_log_arp_net_exit(struct net *net) | |
119 | { | |
120 | nf_log_unset(net, &nf_arp_logger); | |
121 | } | |
122 | ||
123 | static struct pernet_operations nf_log_arp_net_ops = { | |
124 | .init = nf_log_arp_net_init, | |
125 | .exit = nf_log_arp_net_exit, | |
126 | }; | |
127 | ||
128 | static int __init nf_log_arp_init(void) | |
129 | { | |
130 | int ret; | |
131 | ||
132 | ret = register_pernet_subsys(&nf_log_arp_net_ops); | |
133 | if (ret < 0) | |
134 | return ret; | |
135 | ||
8ac2bde2 ML |
136 | ret = nf_log_register(NFPROTO_ARP, &nf_arp_logger); |
137 | if (ret < 0) { | |
138 | pr_err("failed to register logger\n"); | |
139 | goto err1; | |
140 | } | |
141 | ||
35b93951 | 142 | return 0; |
8ac2bde2 ML |
143 | |
144 | err1: | |
145 | unregister_pernet_subsys(&nf_log_arp_net_ops); | |
146 | return ret; | |
35b93951 PNA |
147 | } |
148 | ||
149 | static void __exit nf_log_arp_exit(void) | |
150 | { | |
151 | unregister_pernet_subsys(&nf_log_arp_net_ops); | |
152 | nf_log_unregister(&nf_arp_logger); | |
153 | } | |
154 | ||
155 | module_init(nf_log_arp_init); | |
156 | module_exit(nf_log_arp_exit); | |
157 | ||
158 | MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); | |
159 | MODULE_DESCRIPTION("Netfilter ARP packet logging"); | |
160 | MODULE_LICENSE("GPL"); | |
161 | MODULE_ALIAS_NF_LOGGER(3, 0); |