1/* 2 * Packet matching code for ARP packets. 3 * 4 * Based heavily, if not almost entirely, upon ip_tables.c framework. 5 * 6 * Some ARP specific bits are: 7 * 8 * Copyright (C) 2002 David S. Miller (davem@redhat.com) 9 * 10 */ 11 12#include <linux/kernel.h> 13#include <linux/skbuff.h> 14#include <linux/netdevice.h> 15#include <linux/capability.h> 16#include <linux/if_arp.h> 17#include <linux/kmod.h> 18#include <linux/vmalloc.h> 19#include <linux/proc_fs.h> 20#include <linux/module.h> 21#include <linux/init.h> 22 23#include <asm/uaccess.h> 24#include <linux/mutex.h> 25 26#include <linux/netfilter/x_tables.h> 27#include <linux/netfilter_arp/arp_tables.h> 28 29MODULE_LICENSE("GPL"); 30MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); 31MODULE_DESCRIPTION("arptables core"); 32 33/*#define DEBUG_ARP_TABLES*/ 34/*#define DEBUG_ARP_TABLES_USER*/ 35 36#ifdef DEBUG_ARP_TABLES 37#define dprintf(format, args...) printk(format , ## args) 38#else 39#define dprintf(format, args...) 40#endif 41 42#ifdef DEBUG_ARP_TABLES_USER 43#define duprintf(format, args...) printk(format , ## args) 44#else 45#define duprintf(format, args...) 46#endif 47 48#ifdef CONFIG_NETFILTER_DEBUG 49#define ARP_NF_ASSERT(x) \ 50do { \ 51 if (!(x)) \ 52 printk("ARP_NF_ASSERT: %s:%s:%u\n", \ 53 __FUNCTION__, __FILE__, __LINE__); \ 54} while(0) 55#else 56#define ARP_NF_ASSERT(x) 57#endif 58 59static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap, 60 char *hdr_addr, int len) 61{ 62 int i, ret; 63 64 if (len > ARPT_DEV_ADDR_LEN_MAX) 65 len = ARPT_DEV_ADDR_LEN_MAX; 66 67 ret = 0; 68 for (i = 0; i < len; i++) 69 ret |= (hdr_addr[i] ^ ap->addr[i]) & ap->mask[i]; 70 71 return (ret != 0); 72} 73 74/* Returns whether packet matches rule or not. */ 75static inline int arp_packet_match(const struct arphdr *arphdr, 76 struct net_device *dev, 77 const char *indev, 78 const char *outdev, 79 const struct arpt_arp *arpinfo) 80{ 81 char *arpptr = (char *)(arphdr + 1); 82 char *src_devaddr, *tgt_devaddr; 83 __be32 src_ipaddr, tgt_ipaddr; 84 int i, ret; 85 86#define FWINV(bool,invflg) ((bool) ^ !!(arpinfo->invflags & invflg)) 87 88 if (FWINV((arphdr->ar_op & arpinfo->arpop_mask) != arpinfo->arpop, 89 ARPT_INV_ARPOP)) { 90 dprintf("ARP operation field mismatch.\n"); 91 dprintf("ar_op: %04x info->arpop: %04x info->arpop_mask: %04x\n", 92 arphdr->ar_op, arpinfo->arpop, arpinfo->arpop_mask); 93 return 0; 94 } 95 96 if (FWINV((arphdr->ar_hrd & arpinfo->arhrd_mask) != arpinfo->arhrd, 97 ARPT_INV_ARPHRD)) { 98 dprintf("ARP hardware address format mismatch.\n"); 99 dprintf("ar_hrd: %04x info->arhrd: %04x info->arhrd_mask: %04x\n", 100 arphdr->ar_hrd, arpinfo->arhrd, arpinfo->arhrd_mask); 101 return 0; 102 } 103 104 if (FWINV((arphdr->ar_pro & arpinfo->arpro_mask) != arpinfo->arpro, 105 ARPT_INV_ARPPRO)) { 106 dprintf("ARP protocol address format mismatch.\n"); 107 dprintf("ar_pro: %04x info->arpro: %04x info->arpro_mask: %04x\n", 108 arphdr->ar_pro, arpinfo->arpro, arpinfo->arpro_mask); 109 return 0; 110 } 111 112 if (FWINV((arphdr->ar_hln & arpinfo->arhln_mask) != arpinfo->arhln, 113 ARPT_INV_ARPHLN)) { 114 dprintf("ARP hardware address length mismatch.\n"); 115 dprintf("ar_hln: %02x info->arhln: %02x info->arhln_mask: %02x\n", 116 arphdr->ar_hln, arpinfo->arhln, arpinfo->arhln_mask); 117 return 0; 118 } 119 120 src_devaddr = arpptr; 121 arpptr += dev->addr_len; 122 memcpy(&src_ipaddr, arpptr, sizeof(u32)); 123 arpptr += sizeof(u32); 124 tgt_devaddr = arpptr; 125 arpptr += dev->addr_len; 126 memcpy(&tgt_ipaddr, arpptr, sizeof(u32)); 127 128 if (FWINV(arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, dev->addr_len), 129 ARPT_INV_SRCDEVADDR) || 130 FWINV(arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, dev->addr_len), 131 ARPT_INV_TGTDEVADDR)) { 132 dprintf("Source or target device address mismatch.\n"); 133 134 return 0; 135 } 136 137 if (FWINV((src_ipaddr & arpinfo->smsk.s_addr) != arpinfo->src.s_addr, 138 ARPT_INV_SRCIP) || 139 FWINV(((tgt_ipaddr & arpinfo->tmsk.s_addr) != arpinfo->tgt.s_addr), 140 ARPT_INV_TGTIP)) { 141 dprintf("Source or target IP address mismatch.\n"); 142 143 dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n", 144 NIPQUAD(src_ipaddr), 145 NIPQUAD(arpinfo->smsk.s_addr), 146 NIPQUAD(arpinfo->src.s_addr), 147 arpinfo->invflags & ARPT_INV_SRCIP ? " (INV)" : ""); 148 dprintf("TGT: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n", 149 NIPQUAD(tgt_ipaddr), 150 NIPQUAD(arpinfo->tmsk.s_addr), 151 NIPQUAD(arpinfo->tgt.s_addr), 152 arpinfo->invflags & ARPT_INV_TGTIP ? " (INV)" : ""); 153 return 0; 154 } 155 156 /* Look for ifname matches. */ 157 for (i = 0, ret = 0; i < IFNAMSIZ; i++) { 158 ret |= (indev[i] ^ arpinfo->iniface[i]) 159 & arpinfo->iniface_mask[i]; 160 } 161 162 if (FWINV(ret != 0, ARPT_INV_VIA_IN)) { 163 dprintf("VIA in mismatch (%s vs %s).%s\n", 164 indev, arpinfo->iniface, 165 arpinfo->invflags&ARPT_INV_VIA_IN ?" (INV)":""); 166 return 0; 167 } 168 169 for (i = 0, ret = 0; i < IFNAMSIZ; i++) { 170 ret |= (outdev[i] ^ arpinfo->outiface[i]) 171 & arpinfo->outiface_mask[i]; 172 } 173 174 if (FWINV(ret != 0, ARPT_INV_VIA_OUT)) { 175 dprintf("VIA out mismatch (%s vs %s).%s\n", 176 outdev, arpinfo->outiface, 177 arpinfo->invflags&ARPT_INV_VIA_OUT ?" (INV)":""); 178 return 0; 179 } 180 181 return 1; 182} 183 184static inline int arp_checkentry(const struct arpt_arp *arp) 185{ 186 if (arp->flags & ~ARPT_F_MASK) { 187 duprintf("Unknown flag bits set: %08X\n", 188 arp->flags & ~ARPT_F_MASK); 189 return 0; 190 } 191 if (arp->invflags & ~ARPT_INV_MASK) { 192 duprintf("Unknown invflag bits set: %08X\n", 193 arp->invflags & ~ARPT_INV_MASK); 194 return 0; 195 } 196 197 return 1; 198} 199 200static unsigned int arpt_error(struct sk_buff **pskb, 201 const struct net_device *in, 202 const struct net_device *out, 203 unsigned int hooknum, 204 const struct xt_target *target, 205 const void *targinfo) 206{ 207 if (net_ratelimit()) 208 printk("arp_tables: error: '%s'\n", (char *)targinfo); 209 210 return NF_DROP; 211} 212 213static inline struct arpt_entry *get_entry(void *base, unsigned int offset) 214{ 215 return (struct arpt_entry *)(base + offset); 216} 217 218unsigned int arpt_do_table(struct sk_buff **pskb, 219 unsigned int hook, 220 const struct net_device *in, 221 const struct net_device *out, 222 struct arpt_table *table) 223{ 224 static const char nulldevname[IFNAMSIZ]; 225 unsigned int verdict = NF_DROP; 226 struct arphdr *arp; 227 int hotdrop = 0; 228 struct arpt_entry *e, *back; 229 const char *indev, *outdev; 230 void *table_base; 231 struct xt_table_info *private; 232 233 /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ 234 if (!pskb_may_pull((*pskb), (sizeof(struct arphdr) + 235 (2 * (*pskb)->dev->addr_len) + 236 (2 * sizeof(u32))))) 237 return NF_DROP; 238 239 indev = in ? in->name : nulldevname; 240 outdev = out ? out->name : nulldevname; 241 242 read_lock_bh(&table->lock); 243 private = table->private; 244 table_base = (void *)private->entries[smp_processor_id()]; 245 e = get_entry(table_base, private->hook_entry[hook]); 246 back = get_entry(table_base, private->underflow[hook]); 247 248 arp = arp_hdr(*pskb); 249 do { 250 if (arp_packet_match(arp, (*pskb)->dev, indev, outdev, &e->arp)) { 251 struct arpt_entry_target *t; 252 int hdr_len; 253 254 hdr_len = sizeof(*arp) + (2 * sizeof(struct in_addr)) + 255 (2 * (*pskb)->dev->addr_len); 256 ADD_COUNTER(e->counters, hdr_len, 1); 257 258 t = arpt_get_target(e); 259 260 /* Standard target? */ 261 if (!t->u.kernel.target->target) { 262 int v; 263 264 v = ((struct arpt_standard_target *)t)->verdict; 265 if (v < 0) { 266 /* Pop from stack? */ 267 if (v != ARPT_RETURN) { 268 verdict = (unsigned)(-v) - 1; 269 break; 270 } 271 e = back; 272 back = get_entry(table_base, 273 back->comefrom); 274 continue; 275 } 276 if (table_base + v 277 != (void *)e + e->next_offset) { 278 /* Save old back ptr in next entry */ 279 struct arpt_entry *next 280 = (void *)e + e->next_offset; 281 next->comefrom = 282 (void *)back - table_base; 283 284 /* set back pointer to next entry */ 285 back = next; 286 } 287 288 e = get_entry(table_base, v); 289 } else { 290 /* Targets which reenter must return 291 * abs. verdicts 292 */ 293 verdict = t->u.kernel.target->target(pskb, 294 in, out, 295 hook, 296 t->u.kernel.target, 297 t->data); 298 299 /* Target might have changed stuff. */ 300 arp = arp_hdr(*pskb); 301 302 if (verdict == ARPT_CONTINUE) 303 e = (void *)e + e->next_offset; 304 else 305 /* Verdict */ 306 break; 307 } 308 } else { 309 e = (void *)e + e->next_offset; 310 } 311 } while (!hotdrop); 312 read_unlock_bh(&table->lock); 313 314 if (hotdrop) 315 return NF_DROP; 316 else 317 return verdict; 318} 319 320/* All zeroes == unconditional rule. */ 321static inline int unconditional(const struct arpt_arp *arp) 322{ 323 unsigned int i; 324 325 for (i = 0; i < sizeof(*arp)/sizeof(__u32); i++) 326 if (((__u32 *)arp)[i]) 327 return 0; 328 329 return 1; 330} 331 332/* Figures out from what hook each rule can be called: returns 0 if 333 * there are loops. Puts hook bitmask in comefrom. 334 */ 335static int mark_source_chains(struct xt_table_info *newinfo, 336 unsigned int valid_hooks, void *entry0) 337{ 338 unsigned int hook; 339 340 /* No recursion; use packet counter to save back ptrs (reset 341 * to 0 as we leave), and comefrom to save source hook bitmask. 342 */ 343 for (hook = 0; hook < NF_ARP_NUMHOOKS; hook++) { 344 unsigned int pos = newinfo->hook_entry[hook]; 345 struct arpt_entry *e 346 = (struct arpt_entry *)(entry0 + pos); 347 348 if (!(valid_hooks & (1 << hook))) 349 continue; 350 351 /* Set initial back pointer. */ 352 e->counters.pcnt = pos; 353 354 for (;;) { 355 struct arpt_standard_target *t 356 = (void *)arpt_get_target(e); 357 int visited = e->comefrom & (1 << hook); 358 359 if (e->comefrom & (1 << NF_ARP_NUMHOOKS)) { 360 printk("arptables: loop hook %u pos %u %08X.\n", 361 hook, pos, e->comefrom); 362 return 0; 363 } 364 e->comefrom 365 |= ((1 << hook) | (1 << NF_ARP_NUMHOOKS)); 366 367 /* Unconditional return/END. */ 368 if ((e->target_offset == sizeof(struct arpt_entry) 369 && (strcmp(t->target.u.user.name, 370 ARPT_STANDARD_TARGET) == 0) 371 && t->verdict < 0 372 && unconditional(&e->arp)) || visited) { 373 unsigned int oldpos, size; 374 375 if (t->verdict < -NF_MAX_VERDICT - 1) { 376 duprintf("mark_source_chains: bad " 377 "negative verdict (%i)\n", 378 t->verdict); 379 return 0; 380 } 381 382 /* Return: backtrack through the last 383 * big jump. 384 */ 385 do { 386 e->comefrom ^= (1<<NF_ARP_NUMHOOKS); 387 oldpos = pos; 388 pos = e->counters.pcnt; 389 e->counters.pcnt = 0; 390 391 /* We're at the start. */ 392 if (pos == oldpos) 393 goto next; 394 395 e = (struct arpt_entry *) 396 (entry0 + pos); 397 } while (oldpos == pos + e->next_offset); 398 399 /* Move along one */ 400 size = e->next_offset; 401 e = (struct arpt_entry *) 402 (entry0 + pos + size); 403 e->counters.pcnt = pos; 404 pos += size; 405 } else { 406 int newpos = t->verdict; 407 408 if (strcmp(t->target.u.user.name, 409 ARPT_STANDARD_TARGET) == 0 410 && newpos >= 0) { 411 if (newpos > newinfo->size - 412 sizeof(struct arpt_entry)) { 413 duprintf("mark_source_chains: " 414 "bad verdict (%i)\n", 415 newpos); 416 return 0; 417 } 418 419 /* This a jump; chase it. */ 420 duprintf("Jump rule %u -> %u\n", 421 pos, newpos); 422 } else { 423 /* ... this is a fallthru */ 424 newpos = pos + e->next_offset; 425 } 426 e = (struct arpt_entry *) 427 (entry0 + newpos); 428 e->counters.pcnt = pos; 429 pos = newpos; 430 } 431 } 432 next: 433 duprintf("Finished chain %u\n", hook); 434 } 435 return 1; 436} 437 438static inline int standard_check(const struct arpt_entry_target *t, 439 unsigned int max_offset) 440{ 441 /* Check standard info. */ 442 if (t->u.target_size 443 != ARPT_ALIGN(sizeof(struct arpt_standard_target))) { 444 duprintf("arpt_standard_check: target size %u != %Zu\n", 445 t->u.target_size, 446 ARPT_ALIGN(sizeof(struct arpt_standard_target))); 447 return 0; 448 } 449 450 return 1; 451} 452 453static struct arpt_target arpt_standard_target; 454 455static inline int check_entry(struct arpt_entry *e, const char *name, unsigned int size, 456 unsigned int *i) 457{ 458 struct arpt_entry_target *t; 459 struct arpt_target *target; 460 int ret; 461 462 if (!arp_checkentry(&e->arp)) { 463 duprintf("arp_tables: arp check failed %p %s.\n", e, name); 464 return -EINVAL; 465 } 466 467 if (e->target_offset + sizeof(struct arpt_entry_target) > e->next_offset) 468 return -EINVAL; 469 470 t = arpt_get_target(e); 471 if (e->target_offset + t->u.target_size > e->next_offset) 472 return -EINVAL; 473 474 target = try_then_request_module(xt_find_target(NF_ARP, t->u.user.name, 475 t->u.user.revision), 476 "arpt_%s", t->u.user.name); 477 if (IS_ERR(target) || !target) { 478 duprintf("check_entry: `%s' not found\n", t->u.user.name); 479 ret = target ? PTR_ERR(target) : -ENOENT; 480 goto out; 481 } 482 t->u.kernel.target = target; 483 484 ret = xt_check_target(target, NF_ARP, t->u.target_size - sizeof(*t), 485 name, e->comefrom, 0, 0); 486 if (ret) 487 goto err; 488 489 if (t->u.kernel.target == &arpt_standard_target) { 490 if (!standard_check(t, size)) { 491 ret = -EINVAL; 492 goto err; 493 } 494 } else if (t->u.kernel.target->checkentry 495 && !t->u.kernel.target->checkentry(name, e, target, t->data, 496 e->comefrom)) { 497 duprintf("arp_tables: check failed for `%s'.\n", 498 t->u.kernel.target->name); 499 ret = -EINVAL; 500 goto err; 501 } 502 503 (*i)++; 504 return 0; 505err: 506 module_put(t->u.kernel.target->me); 507out: 508 return ret; 509} 510 511static inline int check_entry_size_and_hooks(struct arpt_entry *e, 512 struct xt_table_info *newinfo, 513 unsigned char *base, 514 unsigned char *limit, 515 const unsigned int *hook_entries, 516 const unsigned int *underflows, 517 unsigned int *i) 518{ 519 unsigned int h; 520 521 if ((unsigned long)e % __alignof__(struct arpt_entry) != 0 522 || (unsigned char *)e + sizeof(struct arpt_entry) >= limit) { 523 duprintf("Bad offset %p\n", e); 524 return -EINVAL; 525 } 526 527 if (e->next_offset 528 < sizeof(struct arpt_entry) + sizeof(struct arpt_entry_target)) { 529 duprintf("checking: element %p size %u\n", 530 e, e->next_offset); 531 return -EINVAL; 532 } 533 534 /* Check hooks & underflows */ 535 for (h = 0; h < NF_ARP_NUMHOOKS; h++) { 536 if ((unsigned char *)e - base == hook_entries[h]) 537 newinfo->hook_entry[h] = hook_entries[h]; 538 if ((unsigned char *)e - base == underflows[h]) 539 newinfo->underflow[h] = underflows[h]; 540 } 541 542 543 /* Clear counters and comefrom */ 544 e->counters = ((struct xt_counters) { 0, 0 }); 545 e->comefrom = 0; 546 547 (*i)++; 548 return 0; 549} 550 551static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i) 552{ 553 struct arpt_entry_target *t; 554 555 if (i && (*i)-- == 0) 556 return 1; 557 558 t = arpt_get_target(e); 559 if (t->u.kernel.target->destroy) 560 t->u.kernel.target->destroy(t->u.kernel.target, t->data); 561 module_put(t->u.kernel.target->me); 562 return 0; 563} 564 565/* Checks and translates the user-supplied table segment (held in 566 * newinfo). 567 */ 568static int translate_table(const char *name, 569 unsigned int valid_hooks, 570 struct xt_table_info *newinfo, 571 void *entry0, 572 unsigned int size, 573 unsigned int number, 574 const unsigned int *hook_entries, 575 const unsigned int *underflows) 576{ 577 unsigned int i; 578 int ret; 579 580 newinfo->size = size; 581 newinfo->number = number; 582 583 /* Init all hooks to impossible value. */ 584 for (i = 0; i < NF_ARP_NUMHOOKS; i++) { 585 newinfo->hook_entry[i] = 0xFFFFFFFF; 586 newinfo->underflow[i] = 0xFFFFFFFF; 587 } 588 589 duprintf("translate_table: size %u\n", newinfo->size); 590 i = 0; 591 592 /* Walk through entries, checking offsets. */ 593 ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size, 594 check_entry_size_and_hooks, 595 newinfo, 596 entry0, 597 entry0 + size, 598 hook_entries, underflows, &i); 599 duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); 600 if (ret != 0) 601 return ret; 602 603 if (i != number) { 604 duprintf("translate_table: %u not %u entries\n", 605 i, number); 606 return -EINVAL; 607 } 608 609 /* Check hooks all assigned */ 610 for (i = 0; i < NF_ARP_NUMHOOKS; i++) { 611 /* Only hooks which are valid */ 612 if (!(valid_hooks & (1 << i))) 613 continue; 614 if (newinfo->hook_entry[i] == 0xFFFFFFFF) { 615 duprintf("Invalid hook entry %u %u\n", 616 i, hook_entries[i]); 617 return -EINVAL; 618 } 619 if (newinfo->underflow[i] == 0xFFFFFFFF) { 620 duprintf("Invalid underflow %u %u\n", 621 i, underflows[i]); 622 return -EINVAL; 623 } 624 } 625 626 if (!mark_source_chains(newinfo, valid_hooks, entry0)) { 627 duprintf("Looping hook\n"); 628 return -ELOOP; 629 } 630 631 /* Finally, each sanity check must pass */ 632 i = 0; 633 ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size, 634 check_entry, name, size, &i); 635 636 if (ret != 0) { 637 ARPT_ENTRY_ITERATE(entry0, newinfo->size, 638 cleanup_entry, &i); 639 return ret; 640 } 641 642 /* And one copy for every other CPU */ 643 for_each_possible_cpu(i) { 644 if (newinfo->entries[i] && newinfo->entries[i] != entry0) 645 memcpy(newinfo->entries[i], entry0, newinfo->size); 646 } 647 648 return ret; 649} 650 651/* Gets counters. */ 652static inline int add_entry_to_counter(const struct arpt_entry *e, 653 struct xt_counters total[], 654 unsigned int *i) 655{ 656 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); 657 658 (*i)++; 659 return 0; 660} 661 662static inline int set_entry_to_counter(const struct arpt_entry *e, 663 struct xt_counters total[], 664 unsigned int *i) 665{ 666 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); 667 668 (*i)++; 669 return 0; 670} 671 672static void get_counters(const struct xt_table_info *t, 673 struct xt_counters counters[]) 674{ 675 unsigned int cpu; 676 unsigned int i; 677 unsigned int curcpu; 678 679 /* Instead of clearing (by a previous call to memset()) 680 * the counters and using adds, we set the counters 681 * with data used by 'current' CPU 682 * We dont care about preemption here. 683 */ 684 curcpu = raw_smp_processor_id(); 685 686 i = 0; 687 ARPT_ENTRY_ITERATE(t->entries[curcpu], 688 t->size, 689 set_entry_to_counter, 690 counters, 691 &i); 692 693 for_each_possible_cpu(cpu) { 694 if (cpu == curcpu) 695 continue; 696 i = 0; 697 ARPT_ENTRY_ITERATE(t->entries[cpu], 698 t->size, 699 add_entry_to_counter, 700 counters, 701 &i); 702 } 703} 704 705static int copy_entries_to_user(unsigned int total_size, 706 struct arpt_table *table, 707 void __user *userptr) 708{ 709 unsigned int off, num, countersize; 710 struct arpt_entry *e; 711 struct xt_counters *counters; 712 struct xt_table_info *private = table->private; 713 int ret = 0; 714 void *loc_cpu_entry; 715 716 /* We need atomic snapshot of counters: rest doesn't change 717 * (other than comefrom, which userspace doesn't care 718 * about). 719 */ 720 countersize = sizeof(struct xt_counters) * private->number; 721 counters = vmalloc_node(countersize, numa_node_id()); 722 723 if (counters == NULL) 724 return -ENOMEM; 725 726 /* First, sum counters... */ 727 write_lock_bh(&table->lock); 728 get_counters(private, counters); 729 write_unlock_bh(&table->lock); 730 731 loc_cpu_entry = private->entries[raw_smp_processor_id()]; 732 /* ... then copy entire thing ... */ 733 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) { 734 ret = -EFAULT; 735 goto free_counters; 736 } 737 738 /* ... then go back and fix counters and names */ 739 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){ 740 struct arpt_entry_target *t; 741 742 e = (struct arpt_entry *)(loc_cpu_entry + off); 743 if (copy_to_user(userptr + off 744 + offsetof(struct arpt_entry, counters), 745 &counters[num], 746 sizeof(counters[num])) != 0) { 747 ret = -EFAULT; 748 goto free_counters; 749 } 750 751 t = arpt_get_target(e); 752 if (copy_to_user(userptr + off + e->target_offset 753 + offsetof(struct arpt_entry_target, 754 u.user.name), 755 t->u.kernel.target->name, 756 strlen(t->u.kernel.target->name)+1) != 0) { 757 ret = -EFAULT; 758 goto free_counters; 759 } 760 } 761 762 free_counters: 763 vfree(counters); 764 return ret; 765} 766 767static int get_entries(const struct arpt_get_entries *entries, 768 struct arpt_get_entries __user *uptr) 769{ 770 int ret; 771 struct arpt_table *t; 772 773 t = xt_find_table_lock(NF_ARP, entries->name); 774 if (t && !IS_ERR(t)) { 775 struct xt_table_info *private = t->private; 776 duprintf("t->private->number = %u\n", 777 private->number); 778 if (entries->size == private->size) 779 ret = copy_entries_to_user(private->size, 780 t, uptr->entrytable); 781 else { 782 duprintf("get_entries: I've got %u not %u!\n", 783 private->size, entries->size); 784 ret = -EINVAL; 785 } 786 module_put(t->me); 787 xt_table_unlock(t); 788 } else 789 ret = t ? PTR_ERR(t) : -ENOENT; 790 791 return ret; 792} 793 794static int do_replace(void __user *user, unsigned int len) 795{ 796 int ret; 797 struct arpt_replace tmp; 798 struct arpt_table *t; 799 struct xt_table_info *newinfo, *oldinfo; 800 struct xt_counters *counters; 801 void *loc_cpu_entry, *loc_cpu_old_entry; 802 803 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) 804 return -EFAULT; 805 806 /* Hack: Causes ipchains to give correct error msg --RR */ 807 if (len != sizeof(tmp) + tmp.size) 808 return -ENOPROTOOPT; 809 810 /* overflow check */ 811 if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS - 812 SMP_CACHE_BYTES) 813 return -ENOMEM; 814 if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters)) 815 return -ENOMEM; 816 817 newinfo = xt_alloc_table_info(tmp.size); 818 if (!newinfo) 819 return -ENOMEM; 820 821 /* choose the copy that is on our node/cpu */ 822 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; 823 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp), 824 tmp.size) != 0) { 825 ret = -EFAULT; 826 goto free_newinfo; 827 } 828 829 counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters)); 830 if (!counters) { 831 ret = -ENOMEM; 832 goto free_newinfo; 833 } 834 835 ret = translate_table(tmp.name, tmp.valid_hooks, 836 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries, 837 tmp.hook_entry, tmp.underflow); 838 if (ret != 0) 839 goto free_newinfo_counters; 840 841 duprintf("arp_tables: Translated table\n"); 842 843 t = try_then_request_module(xt_find_table_lock(NF_ARP, tmp.name), 844 "arptable_%s", tmp.name); 845 if (!t || IS_ERR(t)) { 846 ret = t ? PTR_ERR(t) : -ENOENT; 847 goto free_newinfo_counters_untrans; 848 } 849 850 /* You lied! */ 851 if (tmp.valid_hooks != t->valid_hooks) { 852 duprintf("Valid hook crap: %08X vs %08X\n", 853 tmp.valid_hooks, t->valid_hooks); 854 ret = -EINVAL; 855 goto put_module; 856 } 857 858 oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret); 859 if (!oldinfo) 860 goto put_module; 861 862 /* Update module usage count based on number of rules */ 863 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n", 864 oldinfo->number, oldinfo->initial_entries, newinfo->number); 865 if ((oldinfo->number > oldinfo->initial_entries) || 866 (newinfo->number <= oldinfo->initial_entries)) 867 module_put(t->me); 868 if ((oldinfo->number > oldinfo->initial_entries) && 869 (newinfo->number <= oldinfo->initial_entries)) 870 module_put(t->me); 871 872 /* Get the old counters. */ 873 get_counters(oldinfo, counters); 874 /* Decrease module usage counts and free resource */ 875 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; 876 ARPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL); 877 878 xt_free_table_info(oldinfo); 879 if (copy_to_user(tmp.counters, counters, 880 sizeof(struct xt_counters) * tmp.num_counters) != 0) 881 ret = -EFAULT; 882 vfree(counters); 883 xt_table_unlock(t); 884 return ret; 885 886 put_module: 887 module_put(t->me); 888 xt_table_unlock(t); 889 free_newinfo_counters_untrans: 890 ARPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL); 891 free_newinfo_counters: 892 vfree(counters); 893 free_newinfo: 894 xt_free_table_info(newinfo); 895 return ret; 896} 897 898/* We're lazy, and add to the first CPU; overflow works its fey magic 899 * and everything is OK. 900 */ 901static inline int add_counter_to_entry(struct arpt_entry *e, 902 const struct xt_counters addme[], 903 unsigned int *i) 904{ 905 906 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); 907 908 (*i)++; 909 return 0; 910} 911 912static int do_add_counters(void __user *user, unsigned int len) 913{ 914 unsigned int i; 915 struct xt_counters_info tmp, *paddc; 916 struct arpt_table *t; 917 struct xt_table_info *private; 918 int ret = 0; 919 void *loc_cpu_entry; 920 921 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) 922 return -EFAULT; 923 924 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters)) 925 return -EINVAL; 926 927 paddc = vmalloc(len); 928 if (!paddc) 929 return -ENOMEM; 930 931 if (copy_from_user(paddc, user, len) != 0) { 932 ret = -EFAULT; 933 goto free; 934 } 935 936 t = xt_find_table_lock(NF_ARP, tmp.name); 937 if (!t || IS_ERR(t)) { 938 ret = t ? PTR_ERR(t) : -ENOENT; 939 goto free; 940 } 941 942 write_lock_bh(&t->lock); 943 private = t->private; 944 if (private->number != tmp.num_counters) { 945 ret = -EINVAL; 946 goto unlock_up_free; 947 } 948 949 i = 0; 950 /* Choose the copy that is on our node */ 951 loc_cpu_entry = private->entries[smp_processor_id()]; 952 ARPT_ENTRY_ITERATE(loc_cpu_entry, 953 private->size, 954 add_counter_to_entry, 955 paddc->counters, 956 &i); 957 unlock_up_free: 958 write_unlock_bh(&t->lock); 959 xt_table_unlock(t); 960 module_put(t->me); 961 free: 962 vfree(paddc); 963 964 return ret; 965} 966 967static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) 968{ 969 int ret; 970 971 if (!capable(CAP_NET_ADMIN)) 972 return -EPERM; 973 974 switch (cmd) { 975 case ARPT_SO_SET_REPLACE: 976 ret = do_replace(user, len); 977 break; 978 979 case ARPT_SO_SET_ADD_COUNTERS: 980 ret = do_add_counters(user, len); 981 break; 982 983 default: 984 duprintf("do_arpt_set_ctl: unknown request %i\n", cmd); 985 ret = -EINVAL; 986 } 987 988 return ret; 989} 990 991static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) 992{ 993 int ret; 994 995 if (!capable(CAP_NET_ADMIN)) 996 return -EPERM; 997 998 switch (cmd) { 999 case ARPT_SO_GET_INFO: { 1000 char name[ARPT_TABLE_MAXNAMELEN]; 1001 struct arpt_table *t; 1002 1003 if (*len != sizeof(struct arpt_getinfo)) { 1004 duprintf("length %u != %Zu\n", *len, 1005 sizeof(struct arpt_getinfo)); 1006 ret = -EINVAL; 1007 break; 1008 } 1009 1010 if (copy_from_user(name, user, sizeof(name)) != 0) { 1011 ret = -EFAULT; 1012 break; 1013 } 1014 name[ARPT_TABLE_MAXNAMELEN-1] = '\0'; 1015 1016 t = try_then_request_module(xt_find_table_lock(NF_ARP, name), 1017 "arptable_%s", name); 1018 if (t && !IS_ERR(t)) { 1019 struct arpt_getinfo info; 1020 struct xt_table_info *private = t->private; 1021 1022 info.valid_hooks = t->valid_hooks; 1023 memcpy(info.hook_entry, private->hook_entry, 1024 sizeof(info.hook_entry)); 1025 memcpy(info.underflow, private->underflow, 1026 sizeof(info.underflow)); 1027 info.num_entries = private->number; 1028 info.size = private->size; 1029 strcpy(info.name, name); 1030 1031 if (copy_to_user(user, &info, *len) != 0) 1032 ret = -EFAULT; 1033 else 1034 ret = 0; 1035 xt_table_unlock(t); 1036 module_put(t->me); 1037 } else 1038 ret = t ? PTR_ERR(t) : -ENOENT; 1039 } 1040 break; 1041 1042 case ARPT_SO_GET_ENTRIES: { 1043 struct arpt_get_entries get; 1044 1045 if (*len < sizeof(get)) { 1046 duprintf("get_entries: %u < %Zu\n", *len, sizeof(get)); 1047 ret = -EINVAL; 1048 } else if (copy_from_user(&get, user, sizeof(get)) != 0) { 1049 ret = -EFAULT; 1050 } else if (*len != sizeof(struct arpt_get_entries) + get.size) { 1051 duprintf("get_entries: %u != %Zu\n", *len, 1052 sizeof(struct arpt_get_entries) + get.size); 1053 ret = -EINVAL; 1054 } else 1055 ret = get_entries(&get, user); 1056 break; 1057 } 1058 1059 case ARPT_SO_GET_REVISION_TARGET: { 1060 struct xt_get_revision rev; 1061 1062 if (*len != sizeof(rev)) { 1063 ret = -EINVAL; 1064 break; 1065 } 1066 if (copy_from_user(&rev, user, sizeof(rev)) != 0) { 1067 ret = -EFAULT; 1068 break; 1069 } 1070 1071 try_then_request_module(xt_find_revision(NF_ARP, rev.name, 1072 rev.revision, 1, &ret), 1073 "arpt_%s", rev.name); 1074 break; 1075 } 1076 1077 default: 1078 duprintf("do_arpt_get_ctl: unknown request %i\n", cmd); 1079 ret = -EINVAL; 1080 } 1081 1082 return ret; 1083} 1084 1085int arpt_register_table(struct arpt_table *table, 1086 const struct arpt_replace *repl) 1087{ 1088 int ret; 1089 struct xt_table_info *newinfo; 1090 static struct xt_table_info bootstrap 1091 = { 0, 0, 0, { 0 }, { 0 }, { } }; 1092 void *loc_cpu_entry; 1093 1094 newinfo = xt_alloc_table_info(repl->size); 1095 if (!newinfo) { 1096 ret = -ENOMEM; 1097 return ret; 1098 } 1099 1100 /* choose the copy on our node/cpu */ 1101 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; 1102 memcpy(loc_cpu_entry, repl->entries, repl->size); 1103 1104 ret = translate_table(table->name, table->valid_hooks, 1105 newinfo, loc_cpu_entry, repl->size, 1106 repl->num_entries, 1107 repl->hook_entry, 1108 repl->underflow); 1109 1110 duprintf("arpt_register_table: translate table gives %d\n", ret); 1111 if (ret != 0) { 1112 xt_free_table_info(newinfo); 1113 return ret; 1114 } 1115 1116 ret = xt_register_table(table, &bootstrap, newinfo); 1117 if (ret != 0) { 1118 xt_free_table_info(newinfo); 1119 return ret; 1120 } 1121 1122 return 0; 1123} 1124 1125void arpt_unregister_table(struct arpt_table *table) 1126{ 1127 struct xt_table_info *private; 1128 void *loc_cpu_entry; 1129 1130 private = xt_unregister_table(table); 1131 1132 /* Decrease module usage counts and free resources */ 1133 loc_cpu_entry = private->entries[raw_smp_processor_id()]; 1134 ARPT_ENTRY_ITERATE(loc_cpu_entry, private->size, 1135 cleanup_entry, NULL); 1136 xt_free_table_info(private); 1137} 1138 1139/* The built-in targets: standard (NULL) and error. */ 1140static struct arpt_target arpt_standard_target = { 1141 .name = ARPT_STANDARD_TARGET, 1142 .targetsize = sizeof(int), 1143 .family = NF_ARP, 1144}; 1145 1146static struct arpt_target arpt_error_target = { 1147 .name = ARPT_ERROR_TARGET, 1148 .target = arpt_error, 1149 .targetsize = ARPT_FUNCTION_MAXNAMELEN, 1150 .family = NF_ARP, 1151}; 1152 1153static struct nf_sockopt_ops arpt_sockopts = { 1154 .pf = PF_INET, 1155 .set_optmin = ARPT_BASE_CTL, 1156 .set_optmax = ARPT_SO_SET_MAX+1, 1157 .set = do_arpt_set_ctl, 1158 .get_optmin = ARPT_BASE_CTL, 1159 .get_optmax = ARPT_SO_GET_MAX+1, 1160 .get = do_arpt_get_ctl, 1161}; 1162 1163static int __init arp_tables_init(void) 1164{ 1165 int ret; 1166 1167 ret = xt_proto_init(NF_ARP); 1168 if (ret < 0) 1169 goto err1; 1170 1171 /* Noone else will be downing sem now, so we won't sleep */ 1172 ret = xt_register_target(&arpt_standard_target); 1173 if (ret < 0) 1174 goto err2; 1175 ret = xt_register_target(&arpt_error_target); 1176 if (ret < 0) 1177 goto err3; 1178 1179 /* Register setsockopt */ 1180 ret = nf_register_sockopt(&arpt_sockopts); 1181 if (ret < 0) 1182 goto err4; 1183 1184 printk("arp_tables: (C) 2002 David S. Miller\n"); 1185 return 0; 1186 1187err4: 1188 xt_unregister_target(&arpt_error_target); 1189err3: 1190 xt_unregister_target(&arpt_standard_target); 1191err2: 1192 xt_proto_fini(NF_ARP); 1193err1: 1194 return ret; 1195} 1196 1197static void __exit arp_tables_fini(void) 1198{ 1199 nf_unregister_sockopt(&arpt_sockopts); 1200 xt_unregister_target(&arpt_error_target); 1201 xt_unregister_target(&arpt_standard_target); 1202 xt_proto_fini(NF_ARP); 1203} 1204 1205EXPORT_SYMBOL(arpt_register_table); 1206EXPORT_SYMBOL(arpt_unregister_table); 1207EXPORT_SYMBOL(arpt_do_table); 1208 1209module_init(arp_tables_init); 1210module_exit(arp_tables_fini); 1211