1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <linux/kernel.h> 3 #include <linux/init.h> 4 #include <linux/module.h> 5 #include <linux/proc_fs.h> 6 #include <linux/skbuff.h> 7 #include <linux/netfilter.h> 8 #include <linux/seq_file.h> 9 #include <net/protocol.h> 10 #include <net/netfilter/nf_log.h> 11 12 #include "nf_internals.h" 13 14 /* Internal logging interface, which relies on the real 15 LOG target modules */ 16 17 #define NFLOGGER_NAME_LEN 64 18 19 int sysctl_nf_log_all_netns __read_mostly; 20 EXPORT_SYMBOL(sysctl_nf_log_all_netns); 21 22 static struct nf_logger __rcu *loggers[NFPROTO_NUMPROTO][NF_LOG_TYPE_MAX] __read_mostly; 23 static DEFINE_MUTEX(nf_log_mutex); 24 25 #define nft_log_dereference(logger) \ 26 rcu_dereference_protected(logger, lockdep_is_held(&nf_log_mutex)) 27 28 static struct nf_logger *__find_logger(int pf, const char *str_logger) 29 { 30 struct nf_logger *log; 31 int i; 32 33 for (i = 0; i < NF_LOG_TYPE_MAX; i++) { 34 if (loggers[pf][i] == NULL) 35 continue; 36 37 log = nft_log_dereference(loggers[pf][i]); 38 if (!strncasecmp(str_logger, log->name, strlen(log->name))) 39 return log; 40 } 41 42 return NULL; 43 } 44 45 int nf_log_set(struct net *net, u_int8_t pf, const struct nf_logger *logger) 46 { 47 const struct nf_logger *log; 48 49 if (pf == NFPROTO_UNSPEC || pf >= ARRAY_SIZE(net->nf.nf_loggers)) 50 return -EOPNOTSUPP; 51 52 mutex_lock(&nf_log_mutex); 53 log = nft_log_dereference(net->nf.nf_loggers[pf]); 54 if (log == NULL) 55 rcu_assign_pointer(net->nf.nf_loggers[pf], logger); 56 57 mutex_unlock(&nf_log_mutex); 58 59 return 0; 60 } 61 EXPORT_SYMBOL(nf_log_set); 62 63 void nf_log_unset(struct net *net, const struct nf_logger *logger) 64 { 65 int i; 66 const struct nf_logger *log; 67 68 mutex_lock(&nf_log_mutex); 69 for (i = 0; i < NFPROTO_NUMPROTO; i++) { 70 log = nft_log_dereference(net->nf.nf_loggers[i]); 71 if (log == logger) 72 RCU_INIT_POINTER(net->nf.nf_loggers[i], NULL); 73 } 74 mutex_unlock(&nf_log_mutex); 75 } 76 EXPORT_SYMBOL(nf_log_unset); 77 78 /* return EEXIST if the same logger is registered, 0 on success. */ 79 int nf_log_register(u_int8_t pf, struct nf_logger *logger) 80 { 81 int i; 82 int ret = 0; 83 84 if (pf >= ARRAY_SIZE(init_net.nf.nf_loggers)) 85 return -EINVAL; 86 87 mutex_lock(&nf_log_mutex); 88 89 if (pf == NFPROTO_UNSPEC) { 90 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) { 91 if (rcu_access_pointer(loggers[i][logger->type])) { 92 ret = -EEXIST; 93 goto unlock; 94 } 95 } 96 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) 97 rcu_assign_pointer(loggers[i][logger->type], logger); 98 } else { 99 if (rcu_access_pointer(loggers[pf][logger->type])) { 100 ret = -EEXIST; 101 goto unlock; 102 } 103 rcu_assign_pointer(loggers[pf][logger->type], logger); 104 } 105 106 unlock: 107 mutex_unlock(&nf_log_mutex); 108 return ret; 109 } 110 EXPORT_SYMBOL(nf_log_register); 111 112 void nf_log_unregister(struct nf_logger *logger) 113 { 114 const struct nf_logger *log; 115 int i; 116 117 mutex_lock(&nf_log_mutex); 118 for (i = 0; i < NFPROTO_NUMPROTO; i++) { 119 log = nft_log_dereference(loggers[i][logger->type]); 120 if (log == logger) 121 RCU_INIT_POINTER(loggers[i][logger->type], NULL); 122 } 123 mutex_unlock(&nf_log_mutex); 124 synchronize_rcu(); 125 } 126 EXPORT_SYMBOL(nf_log_unregister); 127 128 int nf_log_bind_pf(struct net *net, u_int8_t pf, 129 const struct nf_logger *logger) 130 { 131 if (pf >= ARRAY_SIZE(net->nf.nf_loggers)) 132 return -EINVAL; 133 mutex_lock(&nf_log_mutex); 134 if (__find_logger(pf, logger->name) == NULL) { 135 mutex_unlock(&nf_log_mutex); 136 return -ENOENT; 137 } 138 rcu_assign_pointer(net->nf.nf_loggers[pf], logger); 139 mutex_unlock(&nf_log_mutex); 140 return 0; 141 } 142 EXPORT_SYMBOL(nf_log_bind_pf); 143 144 void nf_log_unbind_pf(struct net *net, u_int8_t pf) 145 { 146 if (pf >= ARRAY_SIZE(net->nf.nf_loggers)) 147 return; 148 mutex_lock(&nf_log_mutex); 149 RCU_INIT_POINTER(net->nf.nf_loggers[pf], NULL); 150 mutex_unlock(&nf_log_mutex); 151 } 152 EXPORT_SYMBOL(nf_log_unbind_pf); 153 154 int nf_logger_find_get(int pf, enum nf_log_type type) 155 { 156 struct nf_logger *logger; 157 int ret = -ENOENT; 158 159 if (pf == NFPROTO_INET) { 160 ret = nf_logger_find_get(NFPROTO_IPV4, type); 161 if (ret < 0) 162 return ret; 163 164 ret = nf_logger_find_get(NFPROTO_IPV6, type); 165 if (ret < 0) { 166 nf_logger_put(NFPROTO_IPV4, type); 167 return ret; 168 } 169 170 return 0; 171 } 172 173 rcu_read_lock(); 174 logger = rcu_dereference(loggers[pf][type]); 175 if (logger == NULL) 176 goto out; 177 178 if (try_module_get(logger->me)) 179 ret = 0; 180 out: 181 rcu_read_unlock(); 182 return ret; 183 } 184 EXPORT_SYMBOL_GPL(nf_logger_find_get); 185 186 void nf_logger_put(int pf, enum nf_log_type type) 187 { 188 struct nf_logger *logger; 189 190 if (pf == NFPROTO_INET) { 191 nf_logger_put(NFPROTO_IPV4, type); 192 nf_logger_put(NFPROTO_IPV6, type); 193 return; 194 } 195 196 BUG_ON(loggers[pf][type] == NULL); 197 198 rcu_read_lock(); 199 logger = rcu_dereference(loggers[pf][type]); 200 module_put(logger->me); 201 rcu_read_unlock(); 202 } 203 EXPORT_SYMBOL_GPL(nf_logger_put); 204 205 void nf_log_packet(struct net *net, 206 u_int8_t pf, 207 unsigned int hooknum, 208 const struct sk_buff *skb, 209 const struct net_device *in, 210 const struct net_device *out, 211 const struct nf_loginfo *loginfo, 212 const char *fmt, ...) 213 { 214 va_list args; 215 char prefix[NF_LOG_PREFIXLEN]; 216 const struct nf_logger *logger; 217 218 rcu_read_lock(); 219 if (loginfo != NULL) 220 logger = rcu_dereference(loggers[pf][loginfo->type]); 221 else 222 logger = rcu_dereference(net->nf.nf_loggers[pf]); 223 224 if (logger) { 225 va_start(args, fmt); 226 vsnprintf(prefix, sizeof(prefix), fmt, args); 227 va_end(args); 228 logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix); 229 } 230 rcu_read_unlock(); 231 } 232 EXPORT_SYMBOL(nf_log_packet); 233 234 void nf_log_trace(struct net *net, 235 u_int8_t pf, 236 unsigned int hooknum, 237 const struct sk_buff *skb, 238 const struct net_device *in, 239 const struct net_device *out, 240 const struct nf_loginfo *loginfo, const char *fmt, ...) 241 { 242 va_list args; 243 char prefix[NF_LOG_PREFIXLEN]; 244 const struct nf_logger *logger; 245 246 rcu_read_lock(); 247 logger = rcu_dereference(net->nf.nf_loggers[pf]); 248 if (logger) { 249 va_start(args, fmt); 250 vsnprintf(prefix, sizeof(prefix), fmt, args); 251 va_end(args); 252 logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix); 253 } 254 rcu_read_unlock(); 255 } 256 EXPORT_SYMBOL(nf_log_trace); 257 258 #define S_SIZE (1024 - (sizeof(unsigned int) + 1)) 259 260 struct nf_log_buf { 261 unsigned int count; 262 char buf[S_SIZE + 1]; 263 }; 264 static struct nf_log_buf emergency, *emergency_ptr = &emergency; 265 266 __printf(2, 3) int nf_log_buf_add(struct nf_log_buf *m, const char *f, ...) 267 { 268 va_list args; 269 int len; 270 271 if (likely(m->count < S_SIZE)) { 272 va_start(args, f); 273 len = vsnprintf(m->buf + m->count, S_SIZE - m->count, f, args); 274 va_end(args); 275 if (likely(m->count + len < S_SIZE)) { 276 m->count += len; 277 return 0; 278 } 279 } 280 m->count = S_SIZE; 281 printk_once(KERN_ERR KBUILD_MODNAME " please increase S_SIZE\n"); 282 return -1; 283 } 284 EXPORT_SYMBOL_GPL(nf_log_buf_add); 285 286 struct nf_log_buf *nf_log_buf_open(void) 287 { 288 struct nf_log_buf *m = kmalloc(sizeof(*m), GFP_ATOMIC); 289 290 if (unlikely(!m)) { 291 local_bh_disable(); 292 do { 293 m = xchg(&emergency_ptr, NULL); 294 } while (!m); 295 } 296 m->count = 0; 297 return m; 298 } 299 EXPORT_SYMBOL_GPL(nf_log_buf_open); 300 301 void nf_log_buf_close(struct nf_log_buf *m) 302 { 303 m->buf[m->count] = 0; 304 printk("%s\n", m->buf); 305 306 if (likely(m != &emergency)) 307 kfree(m); 308 else { 309 emergency_ptr = m; 310 local_bh_enable(); 311 } 312 } 313 EXPORT_SYMBOL_GPL(nf_log_buf_close); 314 315 #ifdef CONFIG_PROC_FS 316 static void *seq_start(struct seq_file *seq, loff_t *pos) 317 { 318 struct net *net = seq_file_net(seq); 319 320 mutex_lock(&nf_log_mutex); 321 322 if (*pos >= ARRAY_SIZE(net->nf.nf_loggers)) 323 return NULL; 324 325 return pos; 326 } 327 328 static void *seq_next(struct seq_file *s, void *v, loff_t *pos) 329 { 330 struct net *net = seq_file_net(s); 331 332 (*pos)++; 333 334 if (*pos >= ARRAY_SIZE(net->nf.nf_loggers)) 335 return NULL; 336 337 return pos; 338 } 339 340 static void seq_stop(struct seq_file *s, void *v) 341 { 342 mutex_unlock(&nf_log_mutex); 343 } 344 345 static int seq_show(struct seq_file *s, void *v) 346 { 347 loff_t *pos = v; 348 const struct nf_logger *logger; 349 int i; 350 struct net *net = seq_file_net(s); 351 352 logger = nft_log_dereference(net->nf.nf_loggers[*pos]); 353 354 if (!logger) 355 seq_printf(s, "%2lld NONE (", *pos); 356 else 357 seq_printf(s, "%2lld %s (", *pos, logger->name); 358 359 if (seq_has_overflowed(s)) 360 return -ENOSPC; 361 362 for (i = 0; i < NF_LOG_TYPE_MAX; i++) { 363 if (loggers[*pos][i] == NULL) 364 continue; 365 366 logger = nft_log_dereference(loggers[*pos][i]); 367 seq_puts(s, logger->name); 368 if (i == 0 && loggers[*pos][i + 1] != NULL) 369 seq_puts(s, ","); 370 371 if (seq_has_overflowed(s)) 372 return -ENOSPC; 373 } 374 375 seq_puts(s, ")\n"); 376 377 if (seq_has_overflowed(s)) 378 return -ENOSPC; 379 return 0; 380 } 381 382 static const struct seq_operations nflog_seq_ops = { 383 .start = seq_start, 384 .next = seq_next, 385 .stop = seq_stop, 386 .show = seq_show, 387 }; 388 #endif /* PROC_FS */ 389 390 #ifdef CONFIG_SYSCTL 391 static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3]; 392 static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1]; 393 static struct ctl_table_header *nf_log_sysctl_fhdr; 394 395 static struct ctl_table nf_log_sysctl_ftable[] = { 396 { 397 .procname = "nf_log_all_netns", 398 .data = &sysctl_nf_log_all_netns, 399 .maxlen = sizeof(sysctl_nf_log_all_netns), 400 .mode = 0644, 401 .proc_handler = proc_dointvec, 402 }, 403 { } 404 }; 405 406 static int nf_log_proc_dostring(struct ctl_table *table, int write, 407 void *buffer, size_t *lenp, loff_t *ppos) 408 { 409 const struct nf_logger *logger; 410 char buf[NFLOGGER_NAME_LEN]; 411 int r = 0; 412 int tindex = (unsigned long)table->extra1; 413 struct net *net = table->extra2; 414 415 if (write) { 416 struct ctl_table tmp = *table; 417 418 /* proc_dostring() can append to existing strings, so we need to 419 * initialize it as an empty string. 420 */ 421 buf[0] = '\0'; 422 tmp.data = buf; 423 r = proc_dostring(&tmp, write, buffer, lenp, ppos); 424 if (r) 425 return r; 426 427 if (!strcmp(buf, "NONE")) { 428 nf_log_unbind_pf(net, tindex); 429 return 0; 430 } 431 mutex_lock(&nf_log_mutex); 432 logger = __find_logger(tindex, buf); 433 if (logger == NULL) { 434 mutex_unlock(&nf_log_mutex); 435 return -ENOENT; 436 } 437 rcu_assign_pointer(net->nf.nf_loggers[tindex], logger); 438 mutex_unlock(&nf_log_mutex); 439 } else { 440 struct ctl_table tmp = *table; 441 442 tmp.data = buf; 443 mutex_lock(&nf_log_mutex); 444 logger = nft_log_dereference(net->nf.nf_loggers[tindex]); 445 if (!logger) 446 strlcpy(buf, "NONE", sizeof(buf)); 447 else 448 strlcpy(buf, logger->name, sizeof(buf)); 449 mutex_unlock(&nf_log_mutex); 450 r = proc_dostring(&tmp, write, buffer, lenp, ppos); 451 } 452 453 return r; 454 } 455 456 static int netfilter_log_sysctl_init(struct net *net) 457 { 458 int i; 459 struct ctl_table *table; 460 461 table = nf_log_sysctl_table; 462 if (!net_eq(net, &init_net)) { 463 table = kmemdup(nf_log_sysctl_table, 464 sizeof(nf_log_sysctl_table), 465 GFP_KERNEL); 466 if (!table) 467 goto err_alloc; 468 } else { 469 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) { 470 snprintf(nf_log_sysctl_fnames[i], 471 3, "%d", i); 472 nf_log_sysctl_table[i].procname = 473 nf_log_sysctl_fnames[i]; 474 nf_log_sysctl_table[i].maxlen = NFLOGGER_NAME_LEN; 475 nf_log_sysctl_table[i].mode = 0644; 476 nf_log_sysctl_table[i].proc_handler = 477 nf_log_proc_dostring; 478 nf_log_sysctl_table[i].extra1 = 479 (void *)(unsigned long) i; 480 } 481 nf_log_sysctl_fhdr = register_net_sysctl(net, "net/netfilter", 482 nf_log_sysctl_ftable); 483 if (!nf_log_sysctl_fhdr) 484 goto err_freg; 485 } 486 487 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) 488 table[i].extra2 = net; 489 490 net->nf.nf_log_dir_header = register_net_sysctl(net, 491 "net/netfilter/nf_log", 492 table); 493 if (!net->nf.nf_log_dir_header) 494 goto err_reg; 495 496 return 0; 497 498 err_reg: 499 if (!net_eq(net, &init_net)) 500 kfree(table); 501 else 502 unregister_net_sysctl_table(nf_log_sysctl_fhdr); 503 err_freg: 504 err_alloc: 505 return -ENOMEM; 506 } 507 508 static void netfilter_log_sysctl_exit(struct net *net) 509 { 510 struct ctl_table *table; 511 512 table = net->nf.nf_log_dir_header->ctl_table_arg; 513 unregister_net_sysctl_table(net->nf.nf_log_dir_header); 514 if (!net_eq(net, &init_net)) 515 kfree(table); 516 else 517 unregister_net_sysctl_table(nf_log_sysctl_fhdr); 518 } 519 #else 520 static int netfilter_log_sysctl_init(struct net *net) 521 { 522 return 0; 523 } 524 525 static void netfilter_log_sysctl_exit(struct net *net) 526 { 527 } 528 #endif /* CONFIG_SYSCTL */ 529 530 static int __net_init nf_log_net_init(struct net *net) 531 { 532 int ret = -ENOMEM; 533 534 #ifdef CONFIG_PROC_FS 535 if (!proc_create_net("nf_log", 0444, net->nf.proc_netfilter, 536 &nflog_seq_ops, sizeof(struct seq_net_private))) 537 return ret; 538 #endif 539 ret = netfilter_log_sysctl_init(net); 540 if (ret < 0) 541 goto out_sysctl; 542 543 return 0; 544 545 out_sysctl: 546 #ifdef CONFIG_PROC_FS 547 remove_proc_entry("nf_log", net->nf.proc_netfilter); 548 #endif 549 return ret; 550 } 551 552 static void __net_exit nf_log_net_exit(struct net *net) 553 { 554 netfilter_log_sysctl_exit(net); 555 #ifdef CONFIG_PROC_FS 556 remove_proc_entry("nf_log", net->nf.proc_netfilter); 557 #endif 558 } 559 560 static struct pernet_operations nf_log_net_ops = { 561 .init = nf_log_net_init, 562 .exit = nf_log_net_exit, 563 }; 564 565 int __init netfilter_log_init(void) 566 { 567 return register_pernet_subsys(&nf_log_net_ops); 568 } 569