Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
83e96d44 PNA |
2 | /* (C) 1999-2001 Paul `Rusty' Russell |
3 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | |
83e96d44 | 4 | */ |
a81b2ce8 | 5 | |
8ac2bde2 | 6 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
83e96d44 | 7 | |
a81b2ce8 | 8 | #include <linux/kernel.h> |
83e96d44 PNA |
9 | #include <linux/module.h> |
10 | #include <linux/spinlock.h> | |
11 | #include <linux/skbuff.h> | |
12 | #include <linux/if_arp.h> | |
13 | #include <linux/ip.h> | |
14 | #include <net/ipv6.h> | |
15 | #include <net/icmp.h> | |
16 | #include <net/udp.h> | |
17 | #include <net/tcp.h> | |
18 | #include <net/route.h> | |
19 | ||
20 | #include <linux/netfilter.h> | |
e465cccd | 21 | #include <linux/netfilter_bridge.h> |
f5466caa | 22 | #include <linux/netfilter_ipv6.h> |
83e96d44 PNA |
23 | #include <linux/netfilter/xt_LOG.h> |
24 | #include <net/netfilter/nf_log.h> | |
25 | ||
549d2d41 | 26 | static const struct nf_loginfo default_loginfo = { |
83e96d44 PNA |
27 | .type = NF_LOG_TYPE_LOG, |
28 | .u = { | |
29 | .log = { | |
a81b2ce8 | 30 | .level = LOGLEVEL_NOTICE, |
ff107d27 | 31 | .logflags = NF_LOG_DEFAULT_MASK, |
83e96d44 PNA |
32 | }, |
33 | }, | |
34 | }; | |
35 | ||
f11d61e7 FW |
36 | struct arppayload { |
37 | unsigned char mac_src[ETH_ALEN]; | |
38 | unsigned char ip_src[4]; | |
39 | unsigned char mac_dst[ETH_ALEN]; | |
40 | unsigned char ip_dst[4]; | |
41 | }; | |
42 | ||
e465cccd FW |
43 | static void nf_log_dump_vlan(struct nf_log_buf *m, const struct sk_buff *skb) |
44 | { | |
45 | u16 vid; | |
46 | ||
47 | if (!skb_vlan_tag_present(skb)) | |
48 | return; | |
49 | ||
50 | vid = skb_vlan_tag_get(skb); | |
51 | nf_log_buf_add(m, "VPROTO=%04x VID=%u ", ntohs(skb->vlan_proto), vid); | |
52 | } | |
f11d61e7 FW |
53 | static void noinline_for_stack |
54 | dump_arp_packet(struct nf_log_buf *m, | |
55 | const struct nf_loginfo *info, | |
56 | const struct sk_buff *skb, unsigned int nhoff) | |
57 | { | |
58 | const struct arppayload *ap; | |
59 | struct arppayload _arpp; | |
60 | const struct arphdr *ah; | |
61 | unsigned int logflags; | |
62 | struct arphdr _arph; | |
63 | ||
64 | ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph); | |
65 | if (!ah) { | |
66 | nf_log_buf_add(m, "TRUNCATED"); | |
67 | return; | |
68 | } | |
69 | ||
70 | if (info->type == NF_LOG_TYPE_LOG) | |
71 | logflags = info->u.log.logflags; | |
72 | else | |
73 | logflags = NF_LOG_DEFAULT_MASK; | |
74 | ||
75 | if (logflags & NF_LOG_MACDECODE) { | |
76 | nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM ", | |
77 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest); | |
78 | nf_log_dump_vlan(m, skb); | |
79 | nf_log_buf_add(m, "MACPROTO=%04x ", | |
80 | ntohs(eth_hdr(skb)->h_proto)); | |
81 | } | |
82 | ||
83 | nf_log_buf_add(m, "ARP HTYPE=%d PTYPE=0x%04x OPCODE=%d", | |
84 | ntohs(ah->ar_hrd), ntohs(ah->ar_pro), ntohs(ah->ar_op)); | |
85 | /* If it's for Ethernet and the lengths are OK, then log the ARP | |
86 | * payload. | |
87 | */ | |
88 | if (ah->ar_hrd != htons(ARPHRD_ETHER) || | |
89 | ah->ar_hln != ETH_ALEN || | |
90 | ah->ar_pln != sizeof(__be32)) | |
91 | return; | |
92 | ||
93 | ap = skb_header_pointer(skb, sizeof(_arph), sizeof(_arpp), &_arpp); | |
94 | if (!ap) { | |
95 | nf_log_buf_add(m, " INCOMPLETE [%zu bytes]", | |
96 | skb->len - sizeof(_arph)); | |
97 | return; | |
98 | } | |
99 | nf_log_buf_add(m, " MACSRC=%pM IPSRC=%pI4 MACDST=%pM IPDST=%pI4", | |
100 | ap->mac_src, ap->ip_src, ap->mac_dst, ap->ip_dst); | |
101 | } | |
102 | ||
e465cccd FW |
103 | static void |
104 | nf_log_dump_packet_common(struct nf_log_buf *m, u8 pf, | |
105 | unsigned int hooknum, const struct sk_buff *skb, | |
106 | const struct net_device *in, | |
107 | const struct net_device *out, | |
108 | const struct nf_loginfo *loginfo, const char *prefix) | |
109 | { | |
110 | const struct net_device *physoutdev __maybe_unused; | |
111 | const struct net_device *physindev __maybe_unused; | |
112 | ||
113 | nf_log_buf_add(m, KERN_SOH "%c%sIN=%s OUT=%s ", | |
114 | '0' + loginfo->u.log.level, prefix, | |
115 | in ? in->name : "", | |
116 | out ? out->name : ""); | |
117 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) | |
118 | physindev = nf_bridge_get_physindev(skb); | |
119 | if (physindev && in != physindev) | |
120 | nf_log_buf_add(m, "PHYSIN=%s ", physindev->name); | |
121 | physoutdev = nf_bridge_get_physoutdev(skb); | |
122 | if (physoutdev && out != physoutdev) | |
123 | nf_log_buf_add(m, "PHYSOUT=%s ", physoutdev->name); | |
124 | #endif | |
125 | } | |
126 | ||
f11d61e7 FW |
127 | static void nf_log_arp_packet(struct net *net, u_int8_t pf, |
128 | unsigned int hooknum, const struct sk_buff *skb, | |
129 | const struct net_device *in, | |
130 | const struct net_device *out, | |
131 | const struct nf_loginfo *loginfo, | |
132 | const char *prefix) | |
133 | { | |
134 | struct nf_log_buf *m; | |
135 | ||
136 | /* FIXME: Disabled from containers until syslog ns is supported */ | |
137 | if (!net_eq(net, &init_net) && !sysctl_nf_log_all_netns) | |
138 | return; | |
139 | ||
140 | m = nf_log_buf_open(); | |
141 | ||
142 | if (!loginfo) | |
143 | loginfo = &default_loginfo; | |
144 | ||
145 | nf_log_dump_packet_common(m, pf, hooknum, skb, in, out, loginfo, | |
146 | prefix); | |
147 | dump_arp_packet(m, loginfo, skb, 0); | |
148 | ||
149 | nf_log_buf_close(m); | |
150 | } | |
151 | ||
152 | static struct nf_logger nf_arp_logger __read_mostly = { | |
153 | .name = "nf_log_arp", | |
154 | .type = NF_LOG_TYPE_LOG, | |
155 | .logfn = nf_log_arp_packet, | |
156 | .me = THIS_MODULE, | |
157 | }; | |
158 | ||
e465cccd FW |
159 | static void nf_log_dump_sk_uid_gid(struct net *net, struct nf_log_buf *m, |
160 | struct sock *sk) | |
161 | { | |
162 | if (!sk || !sk_fullsock(sk) || !net_eq(net, sock_net(sk))) | |
163 | return; | |
164 | ||
165 | read_lock_bh(&sk->sk_callback_lock); | |
166 | if (sk->sk_socket && sk->sk_socket->file) { | |
167 | const struct cred *cred = sk->sk_socket->file->f_cred; | |
168 | ||
169 | nf_log_buf_add(m, "UID=%u GID=%u ", | |
170 | from_kuid_munged(&init_user_ns, cred->fsuid), | |
171 | from_kgid_munged(&init_user_ns, cred->fsgid)); | |
172 | } | |
173 | read_unlock_bh(&sk->sk_callback_lock); | |
174 | } | |
175 | ||
176 | static noinline_for_stack int | |
177 | nf_log_dump_tcp_header(struct nf_log_buf *m, | |
178 | const struct sk_buff *skb, | |
179 | u8 proto, int fragment, | |
180 | unsigned int offset, | |
181 | unsigned int logflags) | |
182 | { | |
183 | struct tcphdr _tcph; | |
184 | const struct tcphdr *th; | |
185 | ||
186 | /* Max length: 10 "PROTO=TCP " */ | |
187 | nf_log_buf_add(m, "PROTO=TCP "); | |
188 | ||
189 | if (fragment) | |
190 | return 0; | |
191 | ||
192 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | |
193 | th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); | |
194 | if (!th) { | |
195 | nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); | |
196 | return 1; | |
197 | } | |
198 | ||
199 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | |
200 | nf_log_buf_add(m, "SPT=%u DPT=%u ", | |
201 | ntohs(th->source), ntohs(th->dest)); | |
202 | /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ | |
203 | if (logflags & NF_LOG_TCPSEQ) { | |
204 | nf_log_buf_add(m, "SEQ=%u ACK=%u ", | |
205 | ntohl(th->seq), ntohl(th->ack_seq)); | |
206 | } | |
207 | ||
208 | /* Max length: 13 "WINDOW=65535 " */ | |
209 | nf_log_buf_add(m, "WINDOW=%u ", ntohs(th->window)); | |
210 | /* Max length: 9 "RES=0x3C " */ | |
211 | nf_log_buf_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & | |
212 | TCP_RESERVED_BITS) >> 22)); | |
213 | /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ | |
214 | if (th->cwr) | |
215 | nf_log_buf_add(m, "CWR "); | |
216 | if (th->ece) | |
217 | nf_log_buf_add(m, "ECE "); | |
218 | if (th->urg) | |
219 | nf_log_buf_add(m, "URG "); | |
220 | if (th->ack) | |
221 | nf_log_buf_add(m, "ACK "); | |
222 | if (th->psh) | |
223 | nf_log_buf_add(m, "PSH "); | |
224 | if (th->rst) | |
225 | nf_log_buf_add(m, "RST "); | |
226 | if (th->syn) | |
227 | nf_log_buf_add(m, "SYN "); | |
228 | if (th->fin) | |
229 | nf_log_buf_add(m, "FIN "); | |
230 | /* Max length: 11 "URGP=65535 " */ | |
231 | nf_log_buf_add(m, "URGP=%u ", ntohs(th->urg_ptr)); | |
232 | ||
233 | if ((logflags & NF_LOG_TCPOPT) && th->doff * 4 > sizeof(struct tcphdr)) { | |
234 | unsigned int optsize = th->doff * 4 - sizeof(struct tcphdr); | |
235 | u8 _opt[60 - sizeof(struct tcphdr)]; | |
236 | unsigned int i; | |
237 | const u8 *op; | |
238 | ||
239 | op = skb_header_pointer(skb, offset + sizeof(struct tcphdr), | |
240 | optsize, _opt); | |
241 | if (!op) { | |
242 | nf_log_buf_add(m, "OPT (TRUNCATED)"); | |
243 | return 1; | |
244 | } | |
245 | ||
246 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ | |
247 | nf_log_buf_add(m, "OPT ("); | |
248 | for (i = 0; i < optsize; i++) | |
249 | nf_log_buf_add(m, "%02X", op[i]); | |
250 | ||
251 | nf_log_buf_add(m, ") "); | |
252 | } | |
253 | ||
254 | return 0; | |
255 | } | |
256 | ||
257 | static noinline_for_stack int | |
258 | nf_log_dump_udp_header(struct nf_log_buf *m, | |
259 | const struct sk_buff *skb, | |
260 | u8 proto, int fragment, | |
261 | unsigned int offset) | |
262 | { | |
263 | struct udphdr _udph; | |
264 | const struct udphdr *uh; | |
265 | ||
266 | if (proto == IPPROTO_UDP) | |
267 | /* Max length: 10 "PROTO=UDP " */ | |
268 | nf_log_buf_add(m, "PROTO=UDP "); | |
269 | else /* Max length: 14 "PROTO=UDPLITE " */ | |
270 | nf_log_buf_add(m, "PROTO=UDPLITE "); | |
271 | ||
272 | if (fragment) | |
273 | goto out; | |
274 | ||
275 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | |
276 | uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); | |
277 | if (!uh) { | |
278 | nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); | |
279 | ||
280 | return 1; | |
281 | } | |
282 | ||
283 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | |
284 | nf_log_buf_add(m, "SPT=%u DPT=%u LEN=%u ", | |
285 | ntohs(uh->source), ntohs(uh->dest), ntohs(uh->len)); | |
286 | ||
287 | out: | |
288 | return 0; | |
289 | } | |
290 | ||
83e96d44 | 291 | /* One level of recursion won't kill us */ |
db3187ae FW |
292 | static noinline_for_stack void |
293 | dump_ipv4_packet(struct net *net, struct nf_log_buf *m, | |
294 | const struct nf_loginfo *info, | |
295 | const struct sk_buff *skb, unsigned int iphoff) | |
83e96d44 | 296 | { |
83e96d44 PNA |
297 | const struct iphdr *ih; |
298 | unsigned int logflags; | |
db3187ae | 299 | struct iphdr _iph; |
83e96d44 PNA |
300 | |
301 | if (info->type == NF_LOG_TYPE_LOG) | |
302 | logflags = info->u.log.logflags; | |
303 | else | |
ff107d27 | 304 | logflags = NF_LOG_DEFAULT_MASK; |
83e96d44 PNA |
305 | |
306 | ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph); | |
db3187ae | 307 | if (!ih) { |
83e96d44 PNA |
308 | nf_log_buf_add(m, "TRUNCATED"); |
309 | return; | |
310 | } | |
311 | ||
312 | /* Important fields: | |
db3187ae FW |
313 | * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. |
314 | * Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " | |
315 | */ | |
83e96d44 PNA |
316 | nf_log_buf_add(m, "SRC=%pI4 DST=%pI4 ", &ih->saddr, &ih->daddr); |
317 | ||
318 | /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ | |
319 | nf_log_buf_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", | |
320 | ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK, | |
321 | ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id)); | |
322 | ||
323 | /* Max length: 6 "CE DF MF " */ | |
324 | if (ntohs(ih->frag_off) & IP_CE) | |
325 | nf_log_buf_add(m, "CE "); | |
326 | if (ntohs(ih->frag_off) & IP_DF) | |
327 | nf_log_buf_add(m, "DF "); | |
328 | if (ntohs(ih->frag_off) & IP_MF) | |
329 | nf_log_buf_add(m, "MF "); | |
330 | ||
331 | /* Max length: 11 "FRAG:65535 " */ | |
332 | if (ntohs(ih->frag_off) & IP_OFFSET) | |
333 | nf_log_buf_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); | |
334 | ||
8cb2a7d5 | 335 | if ((logflags & NF_LOG_IPOPT) && |
83e96d44 | 336 | ih->ihl * 4 > sizeof(struct iphdr)) { |
83e96d44 | 337 | unsigned char _opt[4 * 15 - sizeof(struct iphdr)]; |
db3187ae | 338 | const unsigned char *op; |
83e96d44 PNA |
339 | unsigned int i, optsize; |
340 | ||
341 | optsize = ih->ihl * 4 - sizeof(struct iphdr); | |
db3187ae | 342 | op = skb_header_pointer(skb, iphoff + sizeof(_iph), |
83e96d44 | 343 | optsize, _opt); |
db3187ae | 344 | if (!op) { |
83e96d44 PNA |
345 | nf_log_buf_add(m, "TRUNCATED"); |
346 | return; | |
347 | } | |
348 | ||
349 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ | |
350 | nf_log_buf_add(m, "OPT ("); | |
351 | for (i = 0; i < optsize; i++) | |
352 | nf_log_buf_add(m, "%02X", op[i]); | |
353 | nf_log_buf_add(m, ") "); | |
354 | } | |
355 | ||
356 | switch (ih->protocol) { | |
357 | case IPPROTO_TCP: | |
358 | if (nf_log_dump_tcp_header(m, skb, ih->protocol, | |
359 | ntohs(ih->frag_off) & IP_OFFSET, | |
db3187ae | 360 | iphoff + ih->ihl * 4, logflags)) |
83e96d44 PNA |
361 | return; |
362 | break; | |
363 | case IPPROTO_UDP: | |
364 | case IPPROTO_UDPLITE: | |
365 | if (nf_log_dump_udp_header(m, skb, ih->protocol, | |
366 | ntohs(ih->frag_off) & IP_OFFSET, | |
db3187ae | 367 | iphoff + ih->ihl * 4)) |
83e96d44 PNA |
368 | return; |
369 | break; | |
370 | case IPPROTO_ICMP: { | |
db3187ae FW |
371 | static const size_t required_len[NR_ICMP_TYPES + 1] = { |
372 | [ICMP_ECHOREPLY] = 4, | |
373 | [ICMP_DEST_UNREACH] = 8 + sizeof(struct iphdr), | |
374 | [ICMP_SOURCE_QUENCH] = 8 + sizeof(struct iphdr), | |
375 | [ICMP_REDIRECT] = 8 + sizeof(struct iphdr), | |
376 | [ICMP_ECHO] = 4, | |
377 | [ICMP_TIME_EXCEEDED] = 8 + sizeof(struct iphdr), | |
378 | [ICMP_PARAMETERPROB] = 8 + sizeof(struct iphdr), | |
379 | [ICMP_TIMESTAMP] = 20, | |
380 | [ICMP_TIMESTAMPREPLY] = 20, | |
381 | [ICMP_ADDRESS] = 12, | |
382 | [ICMP_ADDRESSREPLY] = 12 }; | |
83e96d44 | 383 | const struct icmphdr *ich; |
db3187ae | 384 | struct icmphdr _icmph; |
83e96d44 PNA |
385 | |
386 | /* Max length: 11 "PROTO=ICMP " */ | |
387 | nf_log_buf_add(m, "PROTO=ICMP "); | |
388 | ||
389 | if (ntohs(ih->frag_off) & IP_OFFSET) | |
390 | break; | |
391 | ||
392 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | |
393 | ich = skb_header_pointer(skb, iphoff + ih->ihl * 4, | |
394 | sizeof(_icmph), &_icmph); | |
db3187ae | 395 | if (!ich) { |
83e96d44 | 396 | nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", |
db3187ae | 397 | skb->len - iphoff - ih->ihl * 4); |
83e96d44 PNA |
398 | break; |
399 | } | |
400 | ||
401 | /* Max length: 18 "TYPE=255 CODE=255 " */ | |
402 | nf_log_buf_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code); | |
403 | ||
404 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | |
405 | if (ich->type <= NR_ICMP_TYPES && | |
406 | required_len[ich->type] && | |
db3187ae | 407 | skb->len - iphoff - ih->ihl * 4 < required_len[ich->type]) { |
83e96d44 | 408 | nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", |
db3187ae | 409 | skb->len - iphoff - ih->ihl * 4); |
83e96d44 PNA |
410 | break; |
411 | } | |
412 | ||
413 | switch (ich->type) { | |
414 | case ICMP_ECHOREPLY: | |
415 | case ICMP_ECHO: | |
416 | /* Max length: 19 "ID=65535 SEQ=65535 " */ | |
417 | nf_log_buf_add(m, "ID=%u SEQ=%u ", | |
418 | ntohs(ich->un.echo.id), | |
419 | ntohs(ich->un.echo.sequence)); | |
420 | break; | |
421 | ||
422 | case ICMP_PARAMETERPROB: | |
423 | /* Max length: 14 "PARAMETER=255 " */ | |
424 | nf_log_buf_add(m, "PARAMETER=%u ", | |
425 | ntohl(ich->un.gateway) >> 24); | |
426 | break; | |
427 | case ICMP_REDIRECT: | |
428 | /* Max length: 24 "GATEWAY=255.255.255.255 " */ | |
429 | nf_log_buf_add(m, "GATEWAY=%pI4 ", &ich->un.gateway); | |
a8eceea8 | 430 | fallthrough; |
83e96d44 PNA |
431 | case ICMP_DEST_UNREACH: |
432 | case ICMP_SOURCE_QUENCH: | |
433 | case ICMP_TIME_EXCEEDED: | |
434 | /* Max length: 3+maxlen */ | |
435 | if (!iphoff) { /* Only recurse once. */ | |
436 | nf_log_buf_add(m, "["); | |
f5646501 | 437 | dump_ipv4_packet(net, m, info, skb, |
db3187ae | 438 | iphoff + ih->ihl * 4 + sizeof(_icmph)); |
83e96d44 PNA |
439 | nf_log_buf_add(m, "] "); |
440 | } | |
441 | ||
442 | /* Max length: 10 "MTU=65535 " */ | |
443 | if (ich->type == ICMP_DEST_UNREACH && | |
444 | ich->code == ICMP_FRAG_NEEDED) { | |
445 | nf_log_buf_add(m, "MTU=%u ", | |
446 | ntohs(ich->un.frag.mtu)); | |
447 | } | |
448 | } | |
449 | break; | |
450 | } | |
451 | /* Max Length */ | |
452 | case IPPROTO_AH: { | |
83e96d44 | 453 | const struct ip_auth_hdr *ah; |
db3187ae | 454 | struct ip_auth_hdr _ahdr; |
83e96d44 PNA |
455 | |
456 | if (ntohs(ih->frag_off) & IP_OFFSET) | |
457 | break; | |
458 | ||
459 | /* Max length: 9 "PROTO=AH " */ | |
460 | nf_log_buf_add(m, "PROTO=AH "); | |
461 | ||
462 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | |
db3187ae | 463 | ah = skb_header_pointer(skb, iphoff + ih->ihl * 4, |
83e96d44 | 464 | sizeof(_ahdr), &_ahdr); |
db3187ae | 465 | if (!ah) { |
83e96d44 | 466 | nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", |
db3187ae | 467 | skb->len - iphoff - ih->ihl * 4); |
83e96d44 PNA |
468 | break; |
469 | } | |
470 | ||
471 | /* Length: 15 "SPI=0xF1234567 " */ | |
472 | nf_log_buf_add(m, "SPI=0x%x ", ntohl(ah->spi)); | |
473 | break; | |
474 | } | |
475 | case IPPROTO_ESP: { | |
83e96d44 | 476 | const struct ip_esp_hdr *eh; |
db3187ae | 477 | struct ip_esp_hdr _esph; |
83e96d44 PNA |
478 | |
479 | /* Max length: 10 "PROTO=ESP " */ | |
480 | nf_log_buf_add(m, "PROTO=ESP "); | |
481 | ||
482 | if (ntohs(ih->frag_off) & IP_OFFSET) | |
483 | break; | |
484 | ||
485 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | |
db3187ae | 486 | eh = skb_header_pointer(skb, iphoff + ih->ihl * 4, |
83e96d44 | 487 | sizeof(_esph), &_esph); |
db3187ae | 488 | if (!eh) { |
83e96d44 | 489 | nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", |
db3187ae | 490 | skb->len - iphoff - ih->ihl * 4); |
83e96d44 PNA |
491 | break; |
492 | } | |
493 | ||
494 | /* Length: 15 "SPI=0xF1234567 " */ | |
495 | nf_log_buf_add(m, "SPI=0x%x ", ntohl(eh->spi)); | |
496 | break; | |
497 | } | |
498 | /* Max length: 10 "PROTO 255 " */ | |
499 | default: | |
500 | nf_log_buf_add(m, "PROTO=%u ", ih->protocol); | |
501 | } | |
502 | ||
503 | /* Max length: 15 "UID=4294967295 " */ | |
8cb2a7d5 | 504 | if ((logflags & NF_LOG_UID) && !iphoff) |
f5646501 | 505 | nf_log_dump_sk_uid_gid(net, m, skb->sk); |
83e96d44 PNA |
506 | |
507 | /* Max length: 16 "MARK=0xFFFFFFFF " */ | |
508 | if (!iphoff && skb->mark) | |
509 | nf_log_buf_add(m, "MARK=0x%x ", skb->mark); | |
510 | ||
511 | /* Proto Max log string length */ | |
512 | /* IP: 40+46+6+11+127 = 230 */ | |
513 | /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ | |
514 | /* UDP: 10+max(25,20) = 35 */ | |
515 | /* UDPLITE: 14+max(25,20) = 39 */ | |
516 | /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ | |
517 | /* ESP: 10+max(25)+15 = 50 */ | |
518 | /* AH: 9+max(25)+15 = 49 */ | |
519 | /* unknown: 10 */ | |
520 | ||
521 | /* (ICMP allows recursion one level deep) */ | |
522 | /* maxlen = IP + ICMP + IP + max(TCP,UDP,ICMP,unknown) */ | |
523 | /* maxlen = 230+ 91 + 230 + 252 = 803 */ | |
524 | } | |
525 | ||
f5466caa FW |
526 | static noinline_for_stack void |
527 | dump_ipv6_packet(struct net *net, struct nf_log_buf *m, | |
528 | const struct nf_loginfo *info, | |
529 | const struct sk_buff *skb, unsigned int ip6hoff, | |
530 | int recurse) | |
531 | { | |
532 | const struct ipv6hdr *ih; | |
533 | unsigned int hdrlen = 0; | |
534 | unsigned int logflags; | |
535 | struct ipv6hdr _ip6h; | |
536 | unsigned int ptr; | |
537 | u8 currenthdr; | |
538 | int fragment; | |
539 | ||
540 | if (info->type == NF_LOG_TYPE_LOG) | |
541 | logflags = info->u.log.logflags; | |
542 | else | |
543 | logflags = NF_LOG_DEFAULT_MASK; | |
544 | ||
545 | ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h); | |
546 | if (!ih) { | |
547 | nf_log_buf_add(m, "TRUNCATED"); | |
548 | return; | |
549 | } | |
550 | ||
551 | /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */ | |
552 | nf_log_buf_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr); | |
553 | ||
554 | /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ | |
555 | nf_log_buf_add(m, "LEN=%zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", | |
556 | ntohs(ih->payload_len) + sizeof(struct ipv6hdr), | |
557 | (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20, | |
558 | ih->hop_limit, | |
559 | (ntohl(*(__be32 *)ih) & 0x000fffff)); | |
560 | ||
561 | fragment = 0; | |
562 | ptr = ip6hoff + sizeof(struct ipv6hdr); | |
563 | currenthdr = ih->nexthdr; | |
564 | while (currenthdr != NEXTHDR_NONE && nf_ip6_ext_hdr(currenthdr)) { | |
565 | struct ipv6_opt_hdr _hdr; | |
566 | const struct ipv6_opt_hdr *hp; | |
567 | ||
568 | hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); | |
569 | if (!hp) { | |
570 | nf_log_buf_add(m, "TRUNCATED"); | |
571 | return; | |
572 | } | |
573 | ||
574 | /* Max length: 48 "OPT (...) " */ | |
575 | if (logflags & NF_LOG_IPOPT) | |
576 | nf_log_buf_add(m, "OPT ( "); | |
577 | ||
578 | switch (currenthdr) { | |
579 | case IPPROTO_FRAGMENT: { | |
580 | struct frag_hdr _fhdr; | |
581 | const struct frag_hdr *fh; | |
582 | ||
583 | nf_log_buf_add(m, "FRAG:"); | |
584 | fh = skb_header_pointer(skb, ptr, sizeof(_fhdr), | |
585 | &_fhdr); | |
586 | if (!fh) { | |
587 | nf_log_buf_add(m, "TRUNCATED "); | |
588 | return; | |
589 | } | |
590 | ||
591 | /* Max length: 6 "65535 " */ | |
592 | nf_log_buf_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8); | |
593 | ||
594 | /* Max length: 11 "INCOMPLETE " */ | |
595 | if (fh->frag_off & htons(0x0001)) | |
596 | nf_log_buf_add(m, "INCOMPLETE "); | |
597 | ||
598 | nf_log_buf_add(m, "ID:%08x ", | |
599 | ntohl(fh->identification)); | |
600 | ||
601 | if (ntohs(fh->frag_off) & 0xFFF8) | |
602 | fragment = 1; | |
603 | ||
604 | hdrlen = 8; | |
605 | break; | |
606 | } | |
607 | case IPPROTO_DSTOPTS: | |
608 | case IPPROTO_ROUTING: | |
609 | case IPPROTO_HOPOPTS: | |
610 | if (fragment) { | |
611 | if (logflags & NF_LOG_IPOPT) | |
612 | nf_log_buf_add(m, ")"); | |
613 | return; | |
614 | } | |
615 | hdrlen = ipv6_optlen(hp); | |
616 | break; | |
617 | /* Max Length */ | |
618 | case IPPROTO_AH: | |
619 | if (logflags & NF_LOG_IPOPT) { | |
620 | struct ip_auth_hdr _ahdr; | |
621 | const struct ip_auth_hdr *ah; | |
622 | ||
623 | /* Max length: 3 "AH " */ | |
624 | nf_log_buf_add(m, "AH "); | |
625 | ||
626 | if (fragment) { | |
627 | nf_log_buf_add(m, ")"); | |
628 | return; | |
629 | } | |
630 | ||
631 | ah = skb_header_pointer(skb, ptr, sizeof(_ahdr), | |
632 | &_ahdr); | |
633 | if (!ah) { | |
634 | /* Max length: 26 "INCOMPLETE [65535 bytes] )" */ | |
635 | nf_log_buf_add(m, "INCOMPLETE [%u bytes] )", | |
636 | skb->len - ptr); | |
637 | return; | |
638 | } | |
639 | ||
640 | /* Length: 15 "SPI=0xF1234567 */ | |
641 | nf_log_buf_add(m, "SPI=0x%x ", ntohl(ah->spi)); | |
642 | } | |
643 | ||
644 | hdrlen = ipv6_authlen(hp); | |
645 | break; | |
646 | case IPPROTO_ESP: | |
647 | if (logflags & NF_LOG_IPOPT) { | |
648 | struct ip_esp_hdr _esph; | |
649 | const struct ip_esp_hdr *eh; | |
650 | ||
651 | /* Max length: 4 "ESP " */ | |
652 | nf_log_buf_add(m, "ESP "); | |
653 | ||
654 | if (fragment) { | |
655 | nf_log_buf_add(m, ")"); | |
656 | return; | |
657 | } | |
658 | ||
659 | /* Max length: 26 "INCOMPLETE [65535 bytes] )" */ | |
660 | eh = skb_header_pointer(skb, ptr, sizeof(_esph), | |
661 | &_esph); | |
662 | if (!eh) { | |
663 | nf_log_buf_add(m, "INCOMPLETE [%u bytes] )", | |
664 | skb->len - ptr); | |
665 | return; | |
666 | } | |
667 | ||
668 | /* Length: 16 "SPI=0xF1234567 )" */ | |
669 | nf_log_buf_add(m, "SPI=0x%x )", | |
670 | ntohl(eh->spi)); | |
671 | } | |
672 | return; | |
673 | default: | |
674 | /* Max length: 20 "Unknown Ext Hdr 255" */ | |
675 | nf_log_buf_add(m, "Unknown Ext Hdr %u", currenthdr); | |
676 | return; | |
677 | } | |
678 | if (logflags & NF_LOG_IPOPT) | |
679 | nf_log_buf_add(m, ") "); | |
680 | ||
681 | currenthdr = hp->nexthdr; | |
682 | ptr += hdrlen; | |
683 | } | |
684 | ||
685 | switch (currenthdr) { | |
686 | case IPPROTO_TCP: | |
687 | if (nf_log_dump_tcp_header(m, skb, currenthdr, fragment, | |
688 | ptr, logflags)) | |
689 | return; | |
690 | break; | |
691 | case IPPROTO_UDP: | |
692 | case IPPROTO_UDPLITE: | |
693 | if (nf_log_dump_udp_header(m, skb, currenthdr, fragment, ptr)) | |
694 | return; | |
695 | break; | |
696 | case IPPROTO_ICMPV6: { | |
697 | struct icmp6hdr _icmp6h; | |
698 | const struct icmp6hdr *ic; | |
699 | ||
700 | /* Max length: 13 "PROTO=ICMPv6 " */ | |
701 | nf_log_buf_add(m, "PROTO=ICMPv6 "); | |
702 | ||
703 | if (fragment) | |
704 | break; | |
705 | ||
706 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | |
707 | ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h); | |
708 | if (!ic) { | |
709 | nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", | |
710 | skb->len - ptr); | |
711 | return; | |
712 | } | |
713 | ||
714 | /* Max length: 18 "TYPE=255 CODE=255 " */ | |
715 | nf_log_buf_add(m, "TYPE=%u CODE=%u ", | |
716 | ic->icmp6_type, ic->icmp6_code); | |
717 | ||
718 | switch (ic->icmp6_type) { | |
719 | case ICMPV6_ECHO_REQUEST: | |
720 | case ICMPV6_ECHO_REPLY: | |
721 | /* Max length: 19 "ID=65535 SEQ=65535 " */ | |
722 | nf_log_buf_add(m, "ID=%u SEQ=%u ", | |
723 | ntohs(ic->icmp6_identifier), | |
724 | ntohs(ic->icmp6_sequence)); | |
725 | break; | |
726 | case ICMPV6_MGM_QUERY: | |
727 | case ICMPV6_MGM_REPORT: | |
728 | case ICMPV6_MGM_REDUCTION: | |
729 | break; | |
730 | ||
731 | case ICMPV6_PARAMPROB: | |
732 | /* Max length: 17 "POINTER=ffffffff " */ | |
733 | nf_log_buf_add(m, "POINTER=%08x ", | |
734 | ntohl(ic->icmp6_pointer)); | |
735 | fallthrough; | |
736 | case ICMPV6_DEST_UNREACH: | |
737 | case ICMPV6_PKT_TOOBIG: | |
738 | case ICMPV6_TIME_EXCEED: | |
739 | /* Max length: 3+maxlen */ | |
740 | if (recurse) { | |
741 | nf_log_buf_add(m, "["); | |
742 | dump_ipv6_packet(net, m, info, skb, | |
743 | ptr + sizeof(_icmp6h), 0); | |
744 | nf_log_buf_add(m, "] "); | |
745 | } | |
746 | ||
747 | /* Max length: 10 "MTU=65535 " */ | |
748 | if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) { | |
749 | nf_log_buf_add(m, "MTU=%u ", | |
750 | ntohl(ic->icmp6_mtu)); | |
751 | } | |
752 | } | |
753 | break; | |
754 | } | |
755 | /* Max length: 10 "PROTO=255 " */ | |
756 | default: | |
757 | nf_log_buf_add(m, "PROTO=%u ", currenthdr); | |
758 | } | |
759 | ||
760 | /* Max length: 15 "UID=4294967295 " */ | |
761 | if ((logflags & NF_LOG_UID) && recurse) | |
762 | nf_log_dump_sk_uid_gid(net, m, skb->sk); | |
763 | ||
764 | /* Max length: 16 "MARK=0xFFFFFFFF " */ | |
765 | if (recurse && skb->mark) | |
766 | nf_log_buf_add(m, "MARK=0x%x ", skb->mark); | |
767 | } | |
768 | ||
83e96d44 | 769 | static void dump_ipv4_mac_header(struct nf_log_buf *m, |
db3187ae FW |
770 | const struct nf_loginfo *info, |
771 | const struct sk_buff *skb) | |
83e96d44 PNA |
772 | { |
773 | struct net_device *dev = skb->dev; | |
774 | unsigned int logflags = 0; | |
775 | ||
776 | if (info->type == NF_LOG_TYPE_LOG) | |
777 | logflags = info->u.log.logflags; | |
778 | ||
8cb2a7d5 | 779 | if (!(logflags & NF_LOG_MACDECODE)) |
83e96d44 PNA |
780 | goto fallback; |
781 | ||
782 | switch (dev->type) { | |
783 | case ARPHRD_ETHER: | |
0d9826bc PNA |
784 | nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM ", |
785 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest); | |
786 | nf_log_dump_vlan(m, skb); | |
787 | nf_log_buf_add(m, "MACPROTO=%04x ", | |
83e96d44 PNA |
788 | ntohs(eth_hdr(skb)->h_proto)); |
789 | return; | |
790 | default: | |
791 | break; | |
792 | } | |
793 | ||
794 | fallback: | |
795 | nf_log_buf_add(m, "MAC="); | |
796 | if (dev->hard_header_len && | |
797 | skb->mac_header != skb->network_header) { | |
798 | const unsigned char *p = skb_mac_header(skb); | |
799 | unsigned int i; | |
800 | ||
801 | nf_log_buf_add(m, "%02x", *p++); | |
802 | for (i = 1; i < dev->hard_header_len; i++, p++) | |
803 | nf_log_buf_add(m, ":%02x", *p); | |
804 | } | |
805 | nf_log_buf_add(m, " "); | |
806 | } | |
807 | ||
fab4085f PNA |
808 | static void nf_log_ip_packet(struct net *net, u_int8_t pf, |
809 | unsigned int hooknum, const struct sk_buff *skb, | |
810 | const struct net_device *in, | |
811 | const struct net_device *out, | |
812 | const struct nf_loginfo *loginfo, | |
813 | const char *prefix) | |
83e96d44 PNA |
814 | { |
815 | struct nf_log_buf *m; | |
816 | ||
817 | /* FIXME: Disabled from containers until syslog ns is supported */ | |
2851940f | 818 | if (!net_eq(net, &init_net) && !sysctl_nf_log_all_netns) |
83e96d44 PNA |
819 | return; |
820 | ||
821 | m = nf_log_buf_open(); | |
822 | ||
823 | if (!loginfo) | |
824 | loginfo = &default_loginfo; | |
825 | ||
826 | nf_log_dump_packet_common(m, pf, hooknum, skb, in, | |
827 | out, loginfo, prefix); | |
828 | ||
db3187ae | 829 | if (in) |
83e96d44 PNA |
830 | dump_ipv4_mac_header(m, loginfo, skb); |
831 | ||
f5646501 | 832 | dump_ipv4_packet(net, m, loginfo, skb, 0); |
83e96d44 PNA |
833 | |
834 | nf_log_buf_close(m); | |
835 | } | |
83e96d44 PNA |
836 | |
837 | static struct nf_logger nf_ip_logger __read_mostly = { | |
838 | .name = "nf_log_ipv4", | |
839 | .type = NF_LOG_TYPE_LOG, | |
840 | .logfn = nf_log_ip_packet, | |
841 | .me = THIS_MODULE, | |
842 | }; | |
843 | ||
f5466caa FW |
844 | static void dump_ipv6_mac_header(struct nf_log_buf *m, |
845 | const struct nf_loginfo *info, | |
846 | const struct sk_buff *skb) | |
847 | { | |
848 | struct net_device *dev = skb->dev; | |
849 | unsigned int logflags = 0; | |
850 | ||
851 | if (info->type == NF_LOG_TYPE_LOG) | |
852 | logflags = info->u.log.logflags; | |
853 | ||
854 | if (!(logflags & NF_LOG_MACDECODE)) | |
855 | goto fallback; | |
856 | ||
857 | switch (dev->type) { | |
858 | case ARPHRD_ETHER: | |
859 | nf_log_buf_add(m, "MACSRC=%pM MACDST=%pM ", | |
860 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest); | |
861 | nf_log_dump_vlan(m, skb); | |
862 | nf_log_buf_add(m, "MACPROTO=%04x ", | |
863 | ntohs(eth_hdr(skb)->h_proto)); | |
864 | return; | |
865 | default: | |
866 | break; | |
867 | } | |
868 | ||
869 | fallback: | |
870 | nf_log_buf_add(m, "MAC="); | |
871 | if (dev->hard_header_len && | |
872 | skb->mac_header != skb->network_header) { | |
873 | const unsigned char *p = skb_mac_header(skb); | |
874 | unsigned int len = dev->hard_header_len; | |
875 | unsigned int i; | |
876 | ||
877 | if (dev->type == ARPHRD_SIT) { | |
878 | p -= ETH_HLEN; | |
879 | ||
880 | if (p < skb->head) | |
881 | p = NULL; | |
882 | } | |
883 | ||
884 | if (p) { | |
885 | nf_log_buf_add(m, "%02x", *p++); | |
886 | for (i = 1; i < len; i++) | |
887 | nf_log_buf_add(m, ":%02x", *p++); | |
888 | } | |
889 | nf_log_buf_add(m, " "); | |
890 | ||
891 | if (dev->type == ARPHRD_SIT) { | |
892 | const struct iphdr *iph = | |
893 | (struct iphdr *)skb_mac_header(skb); | |
894 | nf_log_buf_add(m, "TUNNEL=%pI4->%pI4 ", &iph->saddr, | |
895 | &iph->daddr); | |
896 | } | |
897 | } else { | |
898 | nf_log_buf_add(m, " "); | |
899 | } | |
900 | } | |
901 | ||
902 | static void nf_log_ip6_packet(struct net *net, u_int8_t pf, | |
903 | unsigned int hooknum, const struct sk_buff *skb, | |
904 | const struct net_device *in, | |
905 | const struct net_device *out, | |
906 | const struct nf_loginfo *loginfo, | |
907 | const char *prefix) | |
908 | { | |
909 | struct nf_log_buf *m; | |
910 | ||
911 | /* FIXME: Disabled from containers until syslog ns is supported */ | |
912 | if (!net_eq(net, &init_net) && !sysctl_nf_log_all_netns) | |
913 | return; | |
914 | ||
915 | m = nf_log_buf_open(); | |
916 | ||
917 | if (!loginfo) | |
918 | loginfo = &default_loginfo; | |
919 | ||
920 | nf_log_dump_packet_common(m, pf, hooknum, skb, in, out, | |
921 | loginfo, prefix); | |
922 | ||
923 | if (in) | |
924 | dump_ipv6_mac_header(m, loginfo, skb); | |
925 | ||
926 | dump_ipv6_packet(net, m, loginfo, skb, skb_network_offset(skb), 1); | |
927 | ||
928 | nf_log_buf_close(m); | |
929 | } | |
930 | ||
931 | static struct nf_logger nf_ip6_logger __read_mostly = { | |
932 | .name = "nf_log_ipv6", | |
933 | .type = NF_LOG_TYPE_LOG, | |
934 | .logfn = nf_log_ip6_packet, | |
935 | .me = THIS_MODULE, | |
936 | }; | |
937 | ||
1510618e FW |
938 | static void nf_log_netdev_packet(struct net *net, u_int8_t pf, |
939 | unsigned int hooknum, | |
940 | const struct sk_buff *skb, | |
941 | const struct net_device *in, | |
942 | const struct net_device *out, | |
943 | const struct nf_loginfo *loginfo, | |
944 | const char *prefix) | |
945 | { | |
e465cccd FW |
946 | switch (skb->protocol) { |
947 | case htons(ETH_P_IP): | |
948 | nf_log_ip_packet(net, pf, hooknum, skb, in, out, loginfo, prefix); | |
949 | break; | |
950 | case htons(ETH_P_IPV6): | |
951 | nf_log_ip6_packet(net, pf, hooknum, skb, in, out, loginfo, prefix); | |
952 | break; | |
953 | case htons(ETH_P_ARP): | |
954 | case htons(ETH_P_RARP): | |
955 | nf_log_arp_packet(net, pf, hooknum, skb, in, out, loginfo, prefix); | |
956 | break; | |
957 | } | |
1510618e FW |
958 | } |
959 | ||
960 | static struct nf_logger nf_netdev_logger __read_mostly = { | |
961 | .name = "nf_log_netdev", | |
962 | .type = NF_LOG_TYPE_LOG, | |
963 | .logfn = nf_log_netdev_packet, | |
964 | .me = THIS_MODULE, | |
965 | }; | |
966 | ||
77ccee96 FW |
967 | static struct nf_logger nf_bridge_logger __read_mostly = { |
968 | .name = "nf_log_bridge", | |
969 | .type = NF_LOG_TYPE_LOG, | |
970 | .logfn = nf_log_netdev_packet, | |
971 | .me = THIS_MODULE, | |
972 | }; | |
973 | ||
db3187ae | 974 | static int __net_init nf_log_syslog_net_init(struct net *net) |
83e96d44 | 975 | { |
f11d61e7 FW |
976 | int ret = nf_log_set(net, NFPROTO_IPV4, &nf_ip_logger); |
977 | ||
978 | if (ret) | |
979 | return ret; | |
980 | ||
981 | ret = nf_log_set(net, NFPROTO_ARP, &nf_arp_logger); | |
982 | if (ret) | |
983 | goto err1; | |
f5466caa FW |
984 | |
985 | ret = nf_log_set(net, NFPROTO_IPV6, &nf_ip6_logger); | |
986 | if (ret) | |
987 | goto err2; | |
1510618e FW |
988 | |
989 | ret = nf_log_set(net, NFPROTO_NETDEV, &nf_netdev_logger); | |
990 | if (ret) | |
991 | goto err3; | |
77ccee96 FW |
992 | |
993 | ret = nf_log_set(net, NFPROTO_BRIDGE, &nf_bridge_logger); | |
994 | if (ret) | |
995 | goto err4; | |
f5466caa | 996 | return 0; |
77ccee96 FW |
997 | err4: |
998 | nf_log_unset(net, &nf_netdev_logger); | |
1510618e FW |
999 | err3: |
1000 | nf_log_unset(net, &nf_ip6_logger); | |
f5466caa | 1001 | err2: |
f11d61e7 | 1002 | nf_log_unset(net, &nf_arp_logger); |
f5466caa FW |
1003 | err1: |
1004 | nf_log_unset(net, &nf_ip_logger); | |
f11d61e7 | 1005 | return ret; |
83e96d44 PNA |
1006 | } |
1007 | ||
db3187ae | 1008 | static void __net_exit nf_log_syslog_net_exit(struct net *net) |
83e96d44 PNA |
1009 | { |
1010 | nf_log_unset(net, &nf_ip_logger); | |
f11d61e7 | 1011 | nf_log_unset(net, &nf_arp_logger); |
1510618e FW |
1012 | nf_log_unset(net, &nf_ip6_logger); |
1013 | nf_log_unset(net, &nf_netdev_logger); | |
593268dd | 1014 | nf_log_unset(net, &nf_bridge_logger); |
83e96d44 PNA |
1015 | } |
1016 | ||
db3187ae FW |
1017 | static struct pernet_operations nf_log_syslog_net_ops = { |
1018 | .init = nf_log_syslog_net_init, | |
1019 | .exit = nf_log_syslog_net_exit, | |
83e96d44 PNA |
1020 | }; |
1021 | ||
db3187ae | 1022 | static int __init nf_log_syslog_init(void) |
83e96d44 PNA |
1023 | { |
1024 | int ret; | |
1025 | ||
db3187ae | 1026 | ret = register_pernet_subsys(&nf_log_syslog_net_ops); |
83e96d44 PNA |
1027 | if (ret < 0) |
1028 | return ret; | |
1029 | ||
8ac2bde2 | 1030 | ret = nf_log_register(NFPROTO_IPV4, &nf_ip_logger); |
db3187ae | 1031 | if (ret < 0) |
8ac2bde2 | 1032 | goto err1; |
8ac2bde2 | 1033 | |
f11d61e7 FW |
1034 | ret = nf_log_register(NFPROTO_ARP, &nf_arp_logger); |
1035 | if (ret < 0) | |
1036 | goto err2; | |
8ac2bde2 | 1037 | |
f5466caa FW |
1038 | ret = nf_log_register(NFPROTO_IPV6, &nf_ip6_logger); |
1039 | if (ret < 0) | |
1040 | goto err3; | |
1041 | ||
1510618e FW |
1042 | ret = nf_log_register(NFPROTO_NETDEV, &nf_netdev_logger); |
1043 | if (ret < 0) | |
1044 | goto err4; | |
1045 | ||
77ccee96 FW |
1046 | ret = nf_log_register(NFPROTO_BRIDGE, &nf_bridge_logger); |
1047 | if (ret < 0) | |
1048 | goto err5; | |
1049 | ||
f11d61e7 | 1050 | return 0; |
77ccee96 FW |
1051 | err5: |
1052 | nf_log_unregister(&nf_netdev_logger); | |
1510618e FW |
1053 | err4: |
1054 | nf_log_unregister(&nf_ip6_logger); | |
f5466caa | 1055 | err3: |
f11d61e7 | 1056 | nf_log_unregister(&nf_arp_logger); |
f5466caa FW |
1057 | err2: |
1058 | nf_log_unregister(&nf_ip_logger); | |
8ac2bde2 | 1059 | err1: |
f11d61e7 | 1060 | pr_err("failed to register logger\n"); |
db3187ae | 1061 | unregister_pernet_subsys(&nf_log_syslog_net_ops); |
8ac2bde2 | 1062 | return ret; |
83e96d44 PNA |
1063 | } |
1064 | ||
db3187ae | 1065 | static void __exit nf_log_syslog_exit(void) |
83e96d44 | 1066 | { |
db3187ae | 1067 | unregister_pernet_subsys(&nf_log_syslog_net_ops); |
83e96d44 | 1068 | nf_log_unregister(&nf_ip_logger); |
f11d61e7 | 1069 | nf_log_unregister(&nf_arp_logger); |
f5466caa | 1070 | nf_log_unregister(&nf_ip6_logger); |
1510618e | 1071 | nf_log_unregister(&nf_netdev_logger); |
77ccee96 | 1072 | nf_log_unregister(&nf_bridge_logger); |
83e96d44 PNA |
1073 | } |
1074 | ||
db3187ae FW |
1075 | module_init(nf_log_syslog_init); |
1076 | module_exit(nf_log_syslog_exit); | |
83e96d44 PNA |
1077 | |
1078 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | |
db3187ae | 1079 | MODULE_DESCRIPTION("Netfilter syslog packet logging"); |
83e96d44 | 1080 | MODULE_LICENSE("GPL"); |
f11d61e7 | 1081 | MODULE_ALIAS("nf_log_arp"); |
77ccee96 | 1082 | MODULE_ALIAS("nf_log_bridge"); |
db3187ae | 1083 | MODULE_ALIAS("nf_log_ipv4"); |
f5466caa | 1084 | MODULE_ALIAS("nf_log_ipv6"); |
1510618e | 1085 | MODULE_ALIAS("nf_log_netdev"); |
77ccee96 | 1086 | MODULE_ALIAS_NF_LOGGER(AF_BRIDGE, 0); |
fab4085f | 1087 | MODULE_ALIAS_NF_LOGGER(AF_INET, 0); |
f11d61e7 | 1088 | MODULE_ALIAS_NF_LOGGER(3, 0); |
1510618e | 1089 | MODULE_ALIAS_NF_LOGGER(5, 0); /* NFPROTO_NETDEV */ |
f5466caa | 1090 | MODULE_ALIAS_NF_LOGGER(AF_INET6, 0); |