1/* 2 * communication.c, v2.0 July 2002 3 * 4 * Author: Bart De Schuymer 5 * 6 */ 7 8/* 9 * All the userspace/kernel communication is in this file. 10 * The other code should not have to know anything about the way the 11 * kernel likes the structure of the table data. 12 * The other code works with linked lists. So, the translation is done here. 13 */ 14 15#include <getopt.h> 16#include <string.h> 17#include <errno.h> 18#include <stdio.h> 19#include <stdlib.h> 20#include <fcntl.h> 21#include <unistd.h> 22#include <sys/socket.h> 23#include "include/ebtables_u.h" 24 25extern char* hooknames[NF_BR_NUMHOOKS]; 26 27#ifdef KERNEL_64_USERSPACE_32 28#define sparc_cast (uint64_t) 29#else 30#define sparc_cast 31#endif 32 33int sockfd = -1; 34 35static int get_sockfd() 36{ 37 int ret = 0; 38 if (sockfd == -1) { 39 sockfd = socket(AF_INET, SOCK_RAW, PF_INET); 40 if (sockfd < 0) { 41 ebt_print_error("Problem getting a socket, " 42 "you probably don't have the right " 43 "permissions"); 44 ret = -1; 45 } 46 } 47 return ret; 48} 49 50static struct ebt_replace *translate_user2kernel(struct ebt_u_replace *u_repl) 51{ 52 struct ebt_replace *new; 53 struct ebt_u_entry *e; 54 struct ebt_u_match_list *m_l; 55 struct ebt_u_watcher_list *w_l; 56 struct ebt_u_entries *entries; 57 char *p, *base; 58 int i, j; 59 unsigned int entries_size = 0, *chain_offsets; 60 61 new = (struct ebt_replace *)malloc(sizeof(struct ebt_replace)); 62 if (!new) 63 ebt_print_memory(); 64 new->valid_hooks = u_repl->valid_hooks; 65 strcpy(new->name, u_repl->name); 66 new->nentries = u_repl->nentries; 67 new->num_counters = u_repl->num_counters; 68 new->counters = sparc_cast u_repl->counters; 69 chain_offsets = (unsigned int *)malloc(u_repl->num_chains * sizeof(unsigned int)); 70 /* Determine size */ 71 for (i = 0; i < u_repl->num_chains; i++) { 72 if (!(entries = u_repl->chains[i])) 73 continue; 74 chain_offsets[i] = entries_size; 75 entries_size += sizeof(struct ebt_entries); 76 j = 0; 77 e = entries->entries->next; 78 while (e != entries->entries) { 79 j++; 80 entries_size += sizeof(struct ebt_entry); 81 m_l = e->m_list; 82 while (m_l) { 83 entries_size += m_l->m->match_size + 84 sizeof(struct ebt_entry_match); 85 m_l = m_l->next; 86 } 87 w_l = e->w_list; 88 while (w_l) { 89 entries_size += w_l->w->watcher_size + 90 sizeof(struct ebt_entry_watcher); 91 w_l = w_l->next; 92 } 93 entries_size += e->t->target_size + 94 sizeof(struct ebt_entry_target); 95 e = e->next; 96 } 97 /* A little sanity check */ 98 if (j != entries->nentries) 99 ebt_print_bug("Wrong nentries: %d != %d, hook = %s", j, 100 entries->nentries, entries->name); 101 } 102 103 new->entries_size = entries_size; 104 p = (char *)malloc(entries_size); 105 if (!p) 106 ebt_print_memory(); 107 108 /* Put everything in one block */ 109 new->entries = sparc_cast p; 110 for (i = 0; i < u_repl->num_chains; i++) { 111 struct ebt_entries *hlp; 112 113 hlp = (struct ebt_entries *)p; 114 if (!(entries = u_repl->chains[i])) 115 continue; 116 if (i < NF_BR_NUMHOOKS) 117 new->hook_entry[i] = sparc_cast hlp; 118 hlp->nentries = entries->nentries; 119 hlp->policy = entries->policy; 120 strcpy(hlp->name, entries->name); 121 hlp->counter_offset = entries->counter_offset; 122 hlp->distinguisher = 0; /* Make the kernel see the light */ 123 p += sizeof(struct ebt_entries); 124 e = entries->entries->next; 125 while (e != entries->entries) { 126 struct ebt_entry *tmp = (struct ebt_entry *)p; 127 128 tmp->bitmask = e->bitmask | EBT_ENTRY_OR_ENTRIES; 129 tmp->invflags = e->invflags; 130 tmp->ethproto = e->ethproto; 131 strcpy(tmp->in, e->in); 132 strcpy(tmp->out, e->out); 133 strcpy(tmp->logical_in, e->logical_in); 134 strcpy(tmp->logical_out, e->logical_out); 135 memcpy(tmp->sourcemac, e->sourcemac, 136 sizeof(tmp->sourcemac)); 137 memcpy(tmp->sourcemsk, e->sourcemsk, 138 sizeof(tmp->sourcemsk)); 139 memcpy(tmp->destmac, e->destmac, sizeof(tmp->destmac)); 140 memcpy(tmp->destmsk, e->destmsk, sizeof(tmp->destmsk)); 141 142 base = p; 143 p += sizeof(struct ebt_entry); 144 m_l = e->m_list; 145 while (m_l) { 146 memcpy(p, m_l->m, m_l->m->match_size + 147 sizeof(struct ebt_entry_match)); 148 p += m_l->m->match_size + 149 sizeof(struct ebt_entry_match); 150 m_l = m_l->next; 151 } 152 tmp->watchers_offset = p - base; 153 w_l = e->w_list; 154 while (w_l) { 155 memcpy(p, w_l->w, w_l->w->watcher_size + 156 sizeof(struct ebt_entry_watcher)); 157 p += w_l->w->watcher_size + 158 sizeof(struct ebt_entry_watcher); 159 w_l = w_l->next; 160 } 161 tmp->target_offset = p - base; 162 memcpy(p, e->t, e->t->target_size + 163 sizeof(struct ebt_entry_target)); 164 if (!strcmp(e->t->u.name, EBT_STANDARD_TARGET)) { 165 struct ebt_standard_target *st = 166 (struct ebt_standard_target *)p; 167 /* Translate the jump to a udc */ 168 if (st->verdict >= 0) 169 st->verdict = chain_offsets 170 [st->verdict + NF_BR_NUMHOOKS]; 171 } 172 p += e->t->target_size + 173 sizeof(struct ebt_entry_target); 174 tmp->next_offset = p - base; 175 e = e->next; 176 } 177 } 178 179 /* Sanity check */ 180 if (p - (char *)new->entries != new->entries_size) 181 ebt_print_bug("Entries_size bug"); 182 free(chain_offsets); 183 return new; 184} 185 186static void store_table_in_file(char *filename, struct ebt_replace *repl) 187{ 188 char *data; 189 int size; 190 int fd; 191 192 /* Start from an empty file with the correct priviliges */ 193 if ((fd = creat(filename, 0600)) == -1) { 194 ebt_print_error("Couldn't create file %s", filename); 195 return; 196 } 197 198 size = sizeof(struct ebt_replace) + repl->entries_size + 199 repl->nentries * sizeof(struct ebt_counter); 200 data = (char *)malloc(size); 201 if (!data) 202 ebt_print_memory(); 203 memcpy(data, repl, sizeof(struct ebt_replace)); 204 memcpy(data + sizeof(struct ebt_replace), (char *)repl->entries, 205 repl->entries_size); 206 /* Initialize counters to zero, deliver_counters() can update them */ 207 memset(data + sizeof(struct ebt_replace) + repl->entries_size, 208 0, repl->nentries * sizeof(struct ebt_counter)); 209 if (write(fd, data, size) != size) 210 ebt_print_error("Couldn't write everything to file %s", 211 filename); 212 close(fd); 213 free(data); 214} 215 216void ebt_deliver_table(struct ebt_u_replace *u_repl) 217{ 218 socklen_t optlen; 219 struct ebt_replace *repl; 220 221 /* Translate the struct ebt_u_replace to a struct ebt_replace */ 222 repl = translate_user2kernel(u_repl); 223 if (u_repl->filename != NULL) { 224 store_table_in_file(u_repl->filename, repl); 225 goto free_repl; 226 } 227 /* Give the data to the kernel */ 228 optlen = sizeof(struct ebt_replace) + repl->entries_size; 229 if (get_sockfd()) 230 goto free_repl; 231 if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen)) 232 goto free_repl; 233 if (u_repl->command == 8) { /* The ebtables module may not 234 * yet be loaded with --atomic-commit */ 235 ebtables_insmod("ebtables"); 236 if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, 237 repl, optlen)) 238 goto free_repl; 239 } 240 241 ebt_print_error("The kernel doesn't support a certain ebtables" 242 " extension, consider recompiling your kernel or insmod" 243 " the extension"); 244free_repl: 245 if (repl) { 246 free(repl->entries); 247 free(repl); 248 } 249} 250 251static int store_counters_in_file(char *filename, struct ebt_u_replace *repl) 252{ 253 int size = repl->nentries * sizeof(struct ebt_counter), ret = 0; 254 unsigned int entries_size; 255 struct ebt_replace hlp; 256 FILE *file; 257 258 if (!(file = fopen(filename, "r+b"))) { 259 ebt_print_error("Could not open file %s", filename); 260 return -1; 261 } 262 /* Find out entries_size and then set the file pointer to the 263 * counters */ 264 if (fseek(file, (char *)(&hlp.entries_size) - (char *)(&hlp), SEEK_SET) 265 || fread(&entries_size, sizeof(char), sizeof(unsigned int), file) != 266 sizeof(unsigned int) || 267 fseek(file, entries_size + sizeof(struct ebt_replace), SEEK_SET)) { 268 ebt_print_error("File %s is corrupt", filename); 269 ret = -1; 270 goto close_file; 271 } 272 if (fwrite(repl->counters, sizeof(char), size, file) != size) { 273 ebt_print_error("Could not write everything to file %s", 274 filename); 275 ret = -1; 276 } 277close_file: 278 fclose(file); 279 return 0; 280} 281 282/* Gets executed after ebt_deliver_table. Delivers the counters to the kernel 283 * and resets the counterchanges to CNT_NORM */ 284void ebt_deliver_counters(struct ebt_u_replace *u_repl) 285{ 286 struct ebt_counter *old, *new, *newcounters; 287 socklen_t optlen; 288 struct ebt_replace repl; 289 struct ebt_cntchanges *cc = u_repl->cc->next, *cc2; 290 struct ebt_u_entries *entries; 291 struct ebt_u_entry *next = NULL; 292 int i, chainnr = 0; 293 294 if (u_repl->nentries == 0) 295 return; 296 297 newcounters = (struct ebt_counter *) 298 malloc(u_repl->nentries * sizeof(struct ebt_counter)); 299 if (!newcounters) 300 ebt_print_memory(); 301 memset(newcounters, 0, u_repl->nentries * sizeof(struct ebt_counter)); 302 old = u_repl->counters; 303 new = newcounters; 304 while (cc != u_repl->cc) { 305 if (!next || next == entries->entries) { 306 while (chainnr < u_repl->num_chains && (!(entries = u_repl->chains[chainnr]) || 307 (next = entries->entries->next) == entries->entries)) 308 chainnr++; 309 if (chainnr == u_repl->num_chains) 310 break; 311 } 312 if (cc->type == CNT_NORM) { 313 /* 'Normal' rule, meaning we didn't do anything to it 314 * So, we just copy */ 315 *new = *old; 316 next->cnt = *new; 317 next->cnt_surplus.pcnt = next->cnt_surplus.bcnt = 0; 318 old++; /* We've used an old counter */ 319 new++; /* We've set a new counter */ 320 next = next->next; 321 } else if (cc->type == CNT_DEL) { 322 old++; /* Don't use this old counter */ 323 } else { 324 if (cc->type == CNT_CHANGE) { 325 if (cc->change % 3 == 1) 326 new->pcnt = old->pcnt + next->cnt_surplus.pcnt; 327 else if (cc->change % 3 == 2) 328 new->pcnt = old->pcnt - next->cnt_surplus.pcnt; 329 else 330 new->pcnt = next->cnt.pcnt; 331 if (cc->change / 3 == 1) 332 new->bcnt = old->bcnt + next->cnt_surplus.bcnt; 333 else if (cc->change / 3 == 2) 334 new->bcnt = old->bcnt - next->cnt_surplus.bcnt; 335 else 336 new->bcnt = next->cnt.bcnt; 337 } else 338 *new = next->cnt; 339 next->cnt = *new; 340 next->cnt_surplus.pcnt = next->cnt_surplus.bcnt = 0; 341 if (cc->type == CNT_ADD) 342 new++; 343 else { 344 old++; 345 new++; 346 } 347 next = next->next; 348 } 349 cc = cc->next; 350 } 351 352 free(u_repl->counters); 353 u_repl->counters = newcounters; 354 u_repl->num_counters = u_repl->nentries; 355 /* Reset the counterchanges to CNT_NORM and delete the unused cc */ 356 i = 0; 357 cc = u_repl->cc->next; 358 while (cc != u_repl->cc) { 359 if (cc->type == CNT_DEL) { 360 cc->prev->next = cc->next; 361 cc->next->prev = cc->prev; 362 cc2 = cc->next; 363 free(cc); 364 cc = cc2; 365 } else { 366 cc->type = CNT_NORM; 367 cc->change = 0; 368 i++; 369 cc = cc->next; 370 } 371 } 372 if (i != u_repl->nentries) 373 ebt_print_bug("i != u_repl->nentries"); 374 if (u_repl->filename != NULL) { 375 store_counters_in_file(u_repl->filename, u_repl); 376 return; 377 } 378 optlen = u_repl->nentries * sizeof(struct ebt_counter) + 379 sizeof(struct ebt_replace); 380 /* Now put the stuff in the kernel's struct ebt_replace */ 381 repl.counters = sparc_cast u_repl->counters; 382 repl.num_counters = u_repl->num_counters; 383 memcpy(repl.name, u_repl->name, sizeof(repl.name)); 384 385 if (get_sockfd()) 386 return; 387 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen)) 388 ebt_print_bug("Couldn't update kernel counters"); 389} 390 391static int 392ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l) 393{ 394 struct ebt_u_match_list *new; 395 int ret = 0; 396 397 new = (struct ebt_u_match_list *) 398 malloc(sizeof(struct ebt_u_match_list)); 399 if (!new) 400 ebt_print_memory(); 401 new->m = (struct ebt_entry_match *) 402 malloc(m->match_size + sizeof(struct ebt_entry_match)); 403 if (!new->m) 404 ebt_print_memory(); 405 memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match)); 406 new->next = NULL; 407 **l = new; 408 *l = &new->next; 409 if (ebt_find_match(new->m->u.name) == NULL) { 410 ebt_print_error("Kernel match %s unsupported by userspace tool", 411 new->m->u.name); 412 ret = -1; 413 } 414 return ret; 415} 416 417static int 418ebt_translate_watcher(struct ebt_entry_watcher *w, 419 struct ebt_u_watcher_list ***l) 420{ 421 struct ebt_u_watcher_list *new; 422 int ret = 0; 423 424 new = (struct ebt_u_watcher_list *) 425 malloc(sizeof(struct ebt_u_watcher_list)); 426 if (!new) 427 ebt_print_memory(); 428 new->w = (struct ebt_entry_watcher *) 429 malloc(w->watcher_size + sizeof(struct ebt_entry_watcher)); 430 if (!new->w) 431 ebt_print_memory(); 432 memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher)); 433 new->next = NULL; 434 **l = new; 435 *l = &new->next; 436 if (ebt_find_watcher(new->w->u.name) == NULL) { 437 ebt_print_error("Kernel watcher %s unsupported by userspace " 438 "tool", new->w->u.name); 439 ret = -1; 440 } 441 return ret; 442} 443 444static int 445ebt_translate_entry(struct ebt_entry *e, int *hook, int *n, int *cnt, 446 int *totalcnt, struct ebt_u_entry **u_e, struct ebt_u_replace *u_repl, 447 unsigned int valid_hooks, char *base, struct ebt_cntchanges **cc) 448{ 449 /* An entry */ 450 if (e->bitmask & EBT_ENTRY_OR_ENTRIES) { 451 struct ebt_u_entry *new; 452 struct ebt_u_match_list **m_l; 453 struct ebt_u_watcher_list **w_l; 454 struct ebt_entry_target *t; 455 456 new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry)); 457 if (!new) 458 ebt_print_memory(); 459 new->bitmask = e->bitmask; 460 /* 461 * Plain userspace code doesn't know about 462 * EBT_ENTRY_OR_ENTRIES 463 */ 464 new->bitmask &= ~EBT_ENTRY_OR_ENTRIES; 465 new->invflags = e->invflags; 466 new->ethproto = e->ethproto; 467 strcpy(new->in, e->in); 468 strcpy(new->out, e->out); 469 strcpy(new->logical_in, e->logical_in); 470 strcpy(new->logical_out, e->logical_out); 471 memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac)); 472 memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk)); 473 memcpy(new->destmac, e->destmac, sizeof(new->destmac)); 474 memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk)); 475 if (*totalcnt >= u_repl->nentries) 476 ebt_print_bug("*totalcnt >= u_repl->nentries"); 477 new->cnt = u_repl->counters[*totalcnt]; 478 new->cnt_surplus.pcnt = new->cnt_surplus.bcnt = 0; 479 new->cc = *cc; 480 *cc = (*cc)->next; 481 new->m_list = NULL; 482 new->w_list = NULL; 483 new->next = (*u_e)->next; 484 new->next->prev = new; 485 (*u_e)->next = new; 486 new->prev = *u_e; 487 *u_e = new; 488 m_l = &new->m_list; 489 EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l); 490 w_l = &new->w_list; 491 EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l); 492 493 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset); 494 new->t = (struct ebt_entry_target *) 495 malloc(t->target_size + sizeof(struct ebt_entry_target)); 496 if (!new->t) 497 ebt_print_memory(); 498 if (ebt_find_target(t->u.name) == NULL) { 499 ebt_print_error("Kernel target %s unsupported by " 500 "userspace tool", t->u.name); 501 return -1; 502 } 503 memcpy(new->t, t, t->target_size + 504 sizeof(struct ebt_entry_target)); 505 /* Deal with jumps to udc */ 506 if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) { 507 char *tmp = base; 508 int verdict = ((struct ebt_standard_target *)t)->verdict; 509 int i; 510 511 if (verdict >= 0) { 512 tmp += verdict; 513 for (i = NF_BR_NUMHOOKS; i < u_repl->num_chains; i++) 514 if (u_repl->chains[i]->kernel_start == tmp) 515 break; 516 if (i == u_repl->num_chains) 517 ebt_print_bug("Can't find udc for jump"); 518 ((struct ebt_standard_target *)new->t)->verdict = i-NF_BR_NUMHOOKS; 519 } 520 } 521 522 (*cnt)++; 523 (*totalcnt)++; 524 return 0; 525 } else { /* A new chain */ 526 int i; 527 struct ebt_entries *entries = (struct ebt_entries *)e; 528 529 if (*n != *cnt) 530 ebt_print_bug("Nr of entries in the chain is wrong"); 531 *n = entries->nentries; 532 *cnt = 0; 533 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++) 534 if (valid_hooks & (1 << i)) 535 break; 536 *hook = i; 537 *u_e = u_repl->chains[*hook]->entries; 538 return 0; 539 } 540} 541 542/* Initialize all chain headers */ 543static int 544ebt_translate_chains(struct ebt_entry *e, int *hook, 545 struct ebt_u_replace *u_repl, unsigned int valid_hooks) 546{ 547 int i; 548 struct ebt_entries *entries = (struct ebt_entries *)e; 549 struct ebt_u_entries *new; 550 551 if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) { 552 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++) 553 if (valid_hooks & (1 << i)) 554 break; 555 new = (struct ebt_u_entries *)malloc(sizeof(struct ebt_u_entries)); 556 if (!new) 557 ebt_print_memory(); 558 if (i == u_repl->max_chains) 559 ebt_double_chains(u_repl); 560 u_repl->chains[i] = new; 561 if (i >= NF_BR_NUMHOOKS) 562 new->kernel_start = (char *)e; 563 *hook = i; 564 new->nentries = entries->nentries; 565 new->policy = entries->policy; 566 new->entries = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry)); 567 if (!new->entries) 568 ebt_print_memory(); 569 new->entries->next = new->entries->prev = new->entries; 570 new->counter_offset = entries->counter_offset; 571 strcpy(new->name, entries->name); 572 } 573 return 0; 574} 575 576static int retrieve_from_file(char *filename, struct ebt_replace *repl, 577 char command) 578{ 579 FILE *file; 580 char *hlp = NULL, *entries; 581 struct ebt_counter *counters; 582 int size, ret = 0; 583 584 if (!(file = fopen(filename, "r+b"))) { 585 ebt_print_error("Could not open file %s", filename); 586 return -1; 587 } 588 /* Make sure table name is right if command isn't -L or --atomic-commit */ 589 if (command != 'L' && command != 8) { 590 hlp = (char *)malloc(strlen(repl->name) + 1); 591 if (!hlp) 592 ebt_print_memory(); 593 strcpy(hlp, repl->name); 594 } 595 if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file) 596 != sizeof(struct ebt_replace)) { 597 ebt_print_error("File %s is corrupt", filename); 598 ret = -1; 599 goto close_file; 600 } 601 if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) { 602 ebt_print_error("File %s contains wrong table name or is " 603 "corrupt", filename); 604 ret = -1; 605 goto close_file; 606 } else if (!ebt_find_table(repl->name)) { 607 ebt_print_error("File %s contains invalid table name", 608 filename); 609 ret = -1; 610 goto close_file; 611 } 612 613 size = sizeof(struct ebt_replace) + 614 repl->nentries * sizeof(struct ebt_counter) + repl->entries_size; 615 fseek(file, 0, SEEK_END); 616 if (size != ftell(file)) { 617 ebt_print_error("File %s has wrong size", filename); 618 ret = -1; 619 goto close_file; 620 } 621 entries = (char *)malloc(repl->entries_size); 622 if (!entries) 623 ebt_print_memory(); 624 repl->entries = sparc_cast entries; 625 if (repl->nentries) { 626 counters = (struct ebt_counter *) 627 malloc(repl->nentries * sizeof(struct ebt_counter)); 628 repl->counters = sparc_cast counters; 629 if (!repl->counters) 630 ebt_print_memory(); 631 } else 632 repl->counters = sparc_cast NULL; 633 /* Copy entries and counters */ 634 if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) || 635 fread((char *)repl->entries, sizeof(char), repl->entries_size, file) 636 != repl->entries_size || 637 fseek(file, sizeof(struct ebt_replace) + repl->entries_size, 638 SEEK_SET) 639 || fread((char *)repl->counters, sizeof(char), 640 repl->nentries * sizeof(struct ebt_counter), file) 641 != repl->nentries * sizeof(struct ebt_counter)) { 642 ebt_print_error("File %s is corrupt", filename); 643 free(entries); 644 repl->entries = NULL; 645 ret = -1; 646 } 647close_file: 648 fclose(file); 649 free(hlp); 650 return ret; 651} 652 653static int retrieve_from_kernel(struct ebt_replace *repl, char command, 654 int init) 655{ 656 socklen_t optlen; 657 int optname; 658 char *entries; 659 660 optlen = sizeof(struct ebt_replace); 661 if (get_sockfd()) 662 return -1; 663 /* --atomic-init || --init-table */ 664 if (init) 665 optname = EBT_SO_GET_INIT_INFO; 666 else 667 optname = EBT_SO_GET_INFO; 668 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen)) 669 return -1; 670 671 if ( !(entries = (char *)malloc(repl->entries_size)) ) 672 ebt_print_memory(); 673 repl->entries = sparc_cast entries; 674 if (repl->nentries) { 675 struct ebt_counter *counters; 676 677 if (!(counters = (struct ebt_counter *) 678 malloc(repl->nentries * sizeof(struct ebt_counter))) ) 679 ebt_print_memory(); 680 repl->counters = sparc_cast counters; 681 } 682 else 683 repl->counters = sparc_cast NULL; 684 685 /* We want to receive the counters */ 686 repl->num_counters = repl->nentries; 687 optlen += repl->entries_size + repl->num_counters * 688 sizeof(struct ebt_counter); 689 if (init) 690 optname = EBT_SO_GET_INIT_ENTRIES; 691 else 692 optname = EBT_SO_GET_ENTRIES; 693 if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen)) 694 ebt_print_bug("Hmm, what is wrong??? bug#1"); 695 696 return 0; 697} 698 699int ebt_get_table(struct ebt_u_replace *u_repl, int init) 700{ 701 int i, j, k, hook; 702 struct ebt_replace repl; 703 struct ebt_u_entry *u_e; 704 struct ebt_cntchanges *new_cc, *cc; 705 706 strcpy(repl.name, u_repl->name); 707 if (u_repl->filename != NULL) { 708 if (init) 709 ebt_print_bug("Getting initial table data from a file is impossible"); 710 if (retrieve_from_file(u_repl->filename, &repl, u_repl->command)) 711 return -1; 712 /* -L with a wrong table name should be dealt with silently */ 713 strcpy(u_repl->name, repl.name); 714 } else if (retrieve_from_kernel(&repl, u_repl->command, init)) 715 return -1; 716 717 /* Translate the struct ebt_replace to a struct ebt_u_replace */ 718 u_repl->valid_hooks = repl.valid_hooks; 719 u_repl->nentries = repl.nentries; 720 u_repl->num_counters = repl.num_counters; 721 u_repl->counters = repl.counters; 722 u_repl->cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges)); 723 if (!u_repl->cc) 724 ebt_print_memory(); 725 u_repl->cc->next = u_repl->cc->prev = u_repl->cc; 726 cc = u_repl->cc; 727 for (i = 0; i < repl.nentries; i++) { 728 new_cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges)); 729 if (!new_cc) 730 ebt_print_memory(); 731 new_cc->type = CNT_NORM; 732 new_cc->change = 0; 733 new_cc->prev = cc; 734 cc->next = new_cc; 735 cc = new_cc; 736 } 737 if (repl.nentries) { 738 new_cc->next = u_repl->cc; 739 u_repl->cc->prev = new_cc; 740 } 741 u_repl->chains = (struct ebt_u_entries **)calloc(EBT_ORI_MAX_CHAINS, sizeof(void *)); 742 u_repl->max_chains = EBT_ORI_MAX_CHAINS; 743 hook = -1; 744 /* FIXME: Clean up when an error is encountered */ 745 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains, 746 &hook, u_repl, u_repl->valid_hooks); 747 if (hook >= NF_BR_NUMHOOKS) 748 u_repl->num_chains = hook + 1; 749 else 750 u_repl->num_chains = NF_BR_NUMHOOKS; 751 i = 0; /* Holds the expected nr. of entries for the chain */ 752 j = 0; /* Holds the up to now counted entries for the chain */ 753 k = 0; /* Holds the total nr. of entries, should equal u_repl->nentries afterwards */ 754 cc = u_repl->cc->next; 755 hook = -1; 756 EBT_ENTRY_ITERATE((char *)repl.entries, repl.entries_size, 757 ebt_translate_entry, &hook, &i, &j, &k, &u_e, u_repl, 758 u_repl->valid_hooks, (char *)repl.entries, &cc); 759 if (k != u_repl->nentries) 760 ebt_print_bug("Wrong total nentries"); 761 free(repl.entries); 762 return 0; 763} 764