arptables-0.0.5/0000755000175000017500000000000013571215622012451 5ustar pablopabloarptables-0.0.5/libarptc/0000755000175000017500000000000013571215622014251 5ustar pablopabloarptables-0.0.5/libarptc/libarptc_incl.c0000644000175000017500000012414413571215622017230 0ustar pablopablo/* Library which manipulates firewall rules. Version $Revision: 1.7 $ */ /* Architecture of firewall rules is as follows: * * Chains go INPUT, FORWARD, OUTPUT then user chains. * Each user chain starts with an ERROR node. * Every chain ends with an unconditional jump: a RETURN for user chains, * and a POLICY for built-ins. */ /* (C)1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See COPYING for details). */ #ifndef __OPTIMIZE__ STRUCT_ENTRY_TARGET * GET_TARGET(STRUCT_ENTRY *e) { return (void *)e + e->target_offset; } #endif static int sockfd = -1; static void *arptc_fn = NULL; static const char *hooknames[] = { [NF_ARP_IN] "INPUT", [NF_ARP_OUT] "OUTPUT", [NF_ARP_FORWARD] "FORWARD", }; struct counter_map { enum { COUNTER_MAP_NOMAP, COUNTER_MAP_NORMAL_MAP, COUNTER_MAP_ZEROED, COUNTER_MAP_SET } maptype; unsigned int mappos; }; struct chain_cache { char name[TABLE_MAXNAMELEN]; /* This is the first rule in chain. */ STRUCT_ENTRY *start; /* Last rule in chain */ STRUCT_ENTRY *end; }; STRUCT_TC_HANDLE { /* Have changes been made? */ int changed; /* Size in here reflects original state. */ STRUCT_GETINFO info; struct counter_map *counter_map; /* Array of hook names */ const char **hooknames; /* Cached position of chain heads (NULL = no cache). */ unsigned int cache_num_chains; unsigned int cache_num_builtins; struct chain_cache *cache_chain_heads; /* Chain iterator: current chain cache entry. */ struct chain_cache *cache_chain_iteration; /* Rule iterator: terminal rule */ STRUCT_ENTRY *cache_rule_end; /* Number in here reflects current state. */ unsigned int new_number; STRUCT_GET_ENTRIES entries; }; static void set_changed(TC_HANDLE_T h) { if (h->cache_chain_heads) { free(h->cache_chain_heads); h->cache_chain_heads = NULL; h->cache_num_chains = 0; h->cache_chain_iteration = NULL; h->cache_rule_end = NULL; } h->changed = 1; } #ifdef ARPTC_DEBUG static void do_check(TC_HANDLE_T h, unsigned int line); #define CHECK(h) do { if (!getenv("ARPTC_NO_CHECK")) do_check((h), __LINE__); } while(0) #else #define CHECK(h) #endif static inline int get_number(const STRUCT_ENTRY *i, const STRUCT_ENTRY *seek, unsigned int *pos) { if (i == seek) return 1; (*pos)++; return 0; } static unsigned int entry2index(const TC_HANDLE_T h, const STRUCT_ENTRY *seek) { unsigned int pos = 0; if (ENTRY_ITERATE(h->entries.entrytable, h->entries.size, get_number, seek, &pos) == 0) { fprintf(stderr, "ERROR: offset %zu not an entry!\n", (char *)seek - (char *)h->entries.entrytable); abort(); } return pos; } static inline int get_entry_n(STRUCT_ENTRY *i, unsigned int number, unsigned int *pos, STRUCT_ENTRY **pe) { if (*pos == number) { *pe = i; return 1; } (*pos)++; return 0; } static STRUCT_ENTRY * index2entry(TC_HANDLE_T h, unsigned int index) { unsigned int pos = 0; STRUCT_ENTRY *ret = NULL; ENTRY_ITERATE(h->entries.entrytable, h->entries.size, get_entry_n, index, &pos, &ret); return ret; } static inline STRUCT_ENTRY * get_entry(TC_HANDLE_T h, unsigned int offset) { return (STRUCT_ENTRY *)((char *)h->entries.entrytable + offset); } static inline unsigned long entry2offset(const TC_HANDLE_T h, const STRUCT_ENTRY *e) { return (char *)e - (char *)h->entries.entrytable; } static unsigned long index2offset(TC_HANDLE_T h, unsigned int index) { return entry2offset(h, index2entry(h, index)); } static const char * get_errorlabel(TC_HANDLE_T h, unsigned int offset) { STRUCT_ENTRY *e; e = get_entry(h, offset); if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) != 0) { fprintf(stderr, "ERROR: offset %u not an error node!\n", offset); abort(); } return (const char *)GET_TARGET(e)->data; } /* Allocate handle of given size */ static TC_HANDLE_T alloc_handle(const char *tablename, unsigned int size, unsigned int num_rules) { size_t len; TC_HANDLE_T h; len = sizeof(STRUCT_TC_HANDLE) + size + num_rules * sizeof(struct counter_map); if ((h = calloc(1, len)) == NULL) { errno = ENOMEM; return NULL; } h->counter_map = (void *)h + sizeof(STRUCT_TC_HANDLE) + size; strncpy(h->info.name, tablename, sizeof(h->info.name) - 1); strncpy(h->entries.name, tablename, sizeof(h->entries.name) - 1); return h; } TC_HANDLE_T TC_INIT(const char *tablename) { TC_HANDLE_T h; STRUCT_GETINFO info; unsigned int i; socklen_t s, tmp; arptc_fn = TC_INIT; if (sockfd != -1) close(sockfd); sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW); if (sockfd < 0) return NULL; s = sizeof(info); if (RUNTIME_NF_ARP_NUMHOOKS == 2) s -= 2 * sizeof(unsigned int); if (strlen(tablename) >= TABLE_MAXNAMELEN) { errno = EINVAL; return NULL; } strcpy(info.name, tablename); if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0) return NULL; if (RUNTIME_NF_ARP_NUMHOOKS == 2) { memmove(&(info.hook_entry[3]), &(info.hook_entry[2]), 5 * sizeof(unsigned int)); memmove(&(info.underflow[3]), &(info.underflow[2]), 2 * sizeof(unsigned int)); } if ((h = alloc_handle(info.name, info.size, info.num_entries)) == NULL) return NULL; h->hooknames = hooknames; /* Initialize current state */ h->info = info; h->new_number = h->info.num_entries; for (i = 0; i < h->info.num_entries; i++) h->counter_map[i] = ((struct counter_map){COUNTER_MAP_NORMAL_MAP, i}); h->entries.size = h->info.size; tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size; if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, &h->entries, &tmp) < 0) { free(h); return NULL; } CHECK(h); return h; } /* static inline int print_match(const STRUCT_ENTRY_MATCH *m) { printf("Match name: `%s'\n", m->u.user.name); return 0; } */ static int dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle); void TC_DUMP_ENTRIES(const TC_HANDLE_T handle) { CHECK(handle); printf("libarptc v%s. %u entries, %u bytes.\n", ARPTABLES_VERSION, handle->new_number, handle->entries.size); printf("Table `%s'\n", handle->info.name); printf("Hooks: in/out = %u/%u\n", handle->info.hook_entry[NF_ARP_IN], handle->info.hook_entry[NF_ARP_OUT]); printf("Underflows: in/out = %u/%u\n", handle->info.underflow[NF_ARP_IN], handle->info.underflow[NF_ARP_OUT]); ENTRY_ITERATE(handle->entries.entrytable, handle->entries.size, dump_entry, handle); } /* Returns 0 if not hook entry, else hooknumber + 1 */ static inline unsigned int is_hook_entry(STRUCT_ENTRY *e, TC_HANDLE_T h) { unsigned int i; for (i = 0; i < RUNTIME_NF_ARP_NUMHOOKS; i++) { if ((h->info.valid_hooks & (1 << i)) && get_entry(h, h->info.hook_entry[i]) == e) return i+1; } return 0; } static inline int add_chain(STRUCT_ENTRY *e, TC_HANDLE_T h, STRUCT_ENTRY **prev) { unsigned int builtin; /* Last entry. End it. */ if (entry2offset(h, e) + e->next_offset == h->entries.size) { /* This is the ERROR node at end of the table */ h->cache_chain_heads[h->cache_num_chains-1].end = *prev; return 0; } /* We know this is the start of a new chain if it's an ERROR target, or a hook entry point */ if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) == 0) { /* prev was last entry in previous chain */ h->cache_chain_heads[h->cache_num_chains-1].end = *prev; strncpy(h->cache_chain_heads[h->cache_num_chains].name, (const char *)GET_TARGET(e)->data, TABLE_MAXNAMELEN-1); h->cache_chain_heads[h->cache_num_chains].name[TABLE_MAXNAMELEN-1] = '\0'; h->cache_chain_heads[h->cache_num_chains].start = (void *)e + e->next_offset; h->cache_num_chains++; } else if ((builtin = is_hook_entry(e, h)) != 0) { if (h->cache_num_chains > 0) /* prev was last entry in previous chain */ h->cache_chain_heads[h->cache_num_chains-1].end = *prev; strncpy(h->cache_chain_heads[h->cache_num_chains].name, h->hooknames[builtin-1], TABLE_MAXNAMELEN-1); h->cache_chain_heads[h->cache_num_chains].name[TABLE_MAXNAMELEN-1] = '\0'; h->cache_chain_heads[h->cache_num_chains].start = (void *)e; h->cache_num_chains++; } *prev = e; return 0; } static int alphasort(const void *a, const void *b) { return strcmp(((struct chain_cache *)a)->name, ((struct chain_cache *)b)->name); } static int populate_cache(TC_HANDLE_T h) { unsigned int i; STRUCT_ENTRY *prev; /* # chains < # rules / 2 + num builtins - 1 */ h->cache_chain_heads = malloc((h->new_number / 2 + 4) * sizeof(struct chain_cache)); if (!h->cache_chain_heads) { errno = ENOMEM; return 0; } h->cache_num_chains = 0; h->cache_num_builtins = 0; /* Count builtins */ for (i = 0; i < RUNTIME_NF_ARP_NUMHOOKS; i++) { if (h->info.valid_hooks & (1 << i)) h->cache_num_builtins++; } prev = NULL; ENTRY_ITERATE(h->entries.entrytable, h->entries.size, add_chain, h, &prev); qsort(h->cache_chain_heads + h->cache_num_builtins, h->cache_num_chains - h->cache_num_builtins, sizeof(struct chain_cache), alphasort); return 1; } /* Returns cache ptr if found, otherwise NULL. */ static struct chain_cache * find_label(const char *name, TC_HANDLE_T handle) { unsigned int i; if (handle->cache_chain_heads == NULL && !populate_cache(handle)) return NULL; /* FIXME: Linear search through builtins, then binary --RR */ for (i = 0; i < handle->cache_num_chains; i++) { if (strcmp(handle->cache_chain_heads[i].name, name) == 0) return &handle->cache_chain_heads[i]; } return NULL; } /* Does this chain exist? */ int TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle) { return find_label(chain, handle) != NULL; } /* Returns the position of the final (ie. unconditional) element. */ static unsigned int get_chain_end(const TC_HANDLE_T handle, unsigned int start) { unsigned int last_off, off; STRUCT_ENTRY *e; last_off = start; e = get_entry(handle, start); /* Terminate when we meet a error label or a hook entry. */ for (off = start + e->next_offset; off < handle->entries.size; last_off = off, off += e->next_offset) { STRUCT_ENTRY_TARGET *t; unsigned int i; e = get_entry(handle, off); /* We hit an entry point. */ for (i = 0; i < RUNTIME_NF_ARP_NUMHOOKS; i++) { if ((handle->info.valid_hooks & (1 << i)) && off == handle->info.hook_entry[i]) return last_off; } /* We hit a user chain label */ t = GET_TARGET(e); if (strcmp(t->u.user.name, ERROR_TARGET) == 0) return last_off; } /* SHOULD NEVER HAPPEN */ fprintf(stderr, "ERROR: Off end (%u) of chain from %u!\n", handle->entries.size, off); abort(); } /* Iterator functions to run through the chains. */ const char * TC_FIRST_CHAIN(TC_HANDLE_T *handle) { if ((*handle)->cache_chain_heads == NULL && !populate_cache(*handle)) return NULL; (*handle)->cache_chain_iteration = &(*handle)->cache_chain_heads[0]; return (*handle)->cache_chain_iteration->name; } /* Iterator functions to run through the chains. Returns NULL at end. */ const char * TC_NEXT_CHAIN(TC_HANDLE_T *handle) { (*handle)->cache_chain_iteration++; if ((*handle)->cache_chain_iteration - (*handle)->cache_chain_heads == (*handle)->cache_num_chains) return NULL; return (*handle)->cache_chain_iteration->name; } /* Get first rule in the given chain: NULL for empty chain. */ const STRUCT_ENTRY * TC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle) { struct chain_cache *c; c = find_label(chain, *handle); if (!c) { errno = ENOENT; return NULL; } /* Empty chain: single return/policy rule */ if (c->start == c->end) return NULL; (*handle)->cache_rule_end = c->end; return c->start; } /* Returns NULL when rules run out. */ const STRUCT_ENTRY * TC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle) { if ((void *)prev + prev->next_offset == (void *)(*handle)->cache_rule_end) return NULL; return (void *)prev + prev->next_offset; } #if 0 /* How many rules in this chain? */ unsigned int TC_NUM_RULES(const char *chain, TC_HANDLE_T *handle) { unsigned int off = 0; STRUCT_ENTRY *start, *end; CHECK(*handle); if (!find_label(&off, chain, *handle)) { errno = ENOENT; return (unsigned int)-1; } start = get_entry(*handle, off); end = get_entry(*handle, get_chain_end(*handle, off)); return entry2index(*handle, end) - entry2index(*handle, start); } /* Get n'th rule in this chain. */ const STRUCT_ENTRY *TC_GET_RULE(const char *chain, unsigned int n, TC_HANDLE_T *handle) { unsigned int pos = 0, chainindex; CHECK(*handle); if (!find_label(&pos, chain, *handle)) { errno = ENOENT; return NULL; } chainindex = entry2index(*handle, get_entry(*handle, pos)); return index2entry(*handle, chainindex + n); } #endif static const char * target_name(TC_HANDLE_T handle, const STRUCT_ENTRY *ce) { int spos; const unsigned char *data; unsigned int labelidx; STRUCT_ENTRY *jumpto; /* To avoid const warnings */ STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce; if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) != 0) return GET_TARGET(e)->u.user.name; /* Standard target: evaluate */ data = GET_TARGET(e)->data; spos = *(const int *)data; if (spos < 0) { if (spos == RETURN) return LABEL_RETURN; else if (spos == -NF_ACCEPT-1) return LABEL_ACCEPT; else if (spos == -NF_DROP-1) return LABEL_DROP; else if (spos == -NF_QUEUE-1) return LABEL_QUEUE; fprintf(stderr, "ERROR: off %lu/%u not a valid target (%i)\n", entry2offset(handle, e), handle->entries.size, spos); abort(); } jumpto = get_entry(handle, spos); /* Fall through rule */ if (jumpto == (void *)e + e->next_offset) return ""; /* Must point to head of a chain: ie. after error rule */ labelidx = entry2index(handle, jumpto) - 1; return get_errorlabel(handle, index2offset(handle, labelidx)); } /* Returns a pointer to the target name of this position. */ const char *TC_GET_TARGET(const STRUCT_ENTRY *e, TC_HANDLE_T *handle) { return target_name(*handle, e); } /* Is this a built-in chain? Actually returns hook + 1. */ int TC_BUILTIN(const char *chain, const TC_HANDLE_T handle) { unsigned int i; for (i = 0; i < RUNTIME_NF_ARP_NUMHOOKS; i++) { if ((handle->info.valid_hooks & (1 << i)) && handle->hooknames[i] && strcmp(handle->hooknames[i], chain) == 0) return i+1; } return 0; } /* Get the policy of a given built-in chain */ const char * TC_GET_POLICY(const char *chain, STRUCT_COUNTERS *counters, TC_HANDLE_T *handle) { unsigned int start; STRUCT_ENTRY *e; int hook; hook = TC_BUILTIN(chain, *handle); if (hook != 0) start = (*handle)->info.hook_entry[hook-1]; else return NULL; e = get_entry(*handle, get_chain_end(*handle, start)); *counters = e->counters; return target_name(*handle, e); } static int correct_verdict(STRUCT_ENTRY *e, char *base, unsigned int offset, int delta_offset) { STRUCT_STANDARD_TARGET *t = (void *)GET_TARGET(e); unsigned int curr = (char *)e - base; /* Trap: insert of fall-through rule. Don't change fall-through verdict to jump-over-next-rule. */ if (strcmp(t->target.u.user.name, STANDARD_TARGET) == 0 && t->verdict > (int)offset && !(curr == offset && t->verdict == curr + e->next_offset)) { t->verdict += delta_offset; } return 0; } /* Adjusts standard verdict jump positions after an insertion/deletion. */ static int set_verdict(unsigned int offset, int delta_offset, TC_HANDLE_T *handle) { ENTRY_ITERATE((*handle)->entries.entrytable, (*handle)->entries.size, correct_verdict, (char *)(*handle)->entries.entrytable, offset, delta_offset); set_changed(*handle); return 1; } /* If prepend is set, then we are prepending to a chain: if the * insertion position is an entry point, keep the entry point. */ static int insert_rules(unsigned int num_rules, unsigned int rules_size, const STRUCT_ENTRY *insert, unsigned int offset, unsigned int num_rules_offset, int prepend, TC_HANDLE_T *handle) { TC_HANDLE_T newh; STRUCT_GETINFO newinfo; unsigned int i; if (offset >= (*handle)->entries.size) { errno = EINVAL; return 0; } newinfo = (*handle)->info; /* Fix up entry points. */ for (i = 0; i < RUNTIME_NF_ARP_NUMHOOKS; i++) { /* Entry points to START of chain, so keep same if inserting on at that point. */ if ((*handle)->info.hook_entry[i] > offset) newinfo.hook_entry[i] += rules_size; /* Underflow always points to END of chain (policy), so if something is inserted at same point, it should be advanced. */ if ((*handle)->info.underflow[i] >= offset) newinfo.underflow[i] += rules_size; } newh = alloc_handle((*handle)->info.name, (*handle)->entries.size + rules_size, (*handle)->new_number + num_rules); if (!newh) return 0; newh->info = newinfo; /* Copy pre... */ memcpy(newh->entries.entrytable, (*handle)->entries.entrytable,offset); /* ... Insert new ... */ memcpy((char *)newh->entries.entrytable + offset, insert, rules_size); /* ... copy post */ memcpy((char *)newh->entries.entrytable + offset + rules_size, (char *)(*handle)->entries.entrytable + offset, (*handle)->entries.size - offset); /* Move counter map. */ /* Copy pre... */ memcpy(newh->counter_map, (*handle)->counter_map, sizeof(struct counter_map) * num_rules_offset); /* ... copy post */ memcpy(newh->counter_map + num_rules_offset + num_rules, (*handle)->counter_map + num_rules_offset, sizeof(struct counter_map) * ((*handle)->new_number - num_rules_offset)); /* Set intermediates to no counter copy */ for (i = 0; i < num_rules; i++) newh->counter_map[num_rules_offset+i] = ((struct counter_map){ COUNTER_MAP_SET, 0 }); newh->new_number = (*handle)->new_number + num_rules; newh->entries.size = (*handle)->entries.size + rules_size; newh->hooknames = (*handle)->hooknames; if ((*handle)->cache_chain_heads) free((*handle)->cache_chain_heads); free(*handle); *handle = newh; return set_verdict(offset, rules_size, handle); } static int delete_rules(unsigned int num_rules, unsigned int rules_size, unsigned int offset, unsigned int num_rules_offset, TC_HANDLE_T *handle) { unsigned int i; if (offset + rules_size > (*handle)->entries.size) { errno = EINVAL; return 0; } /* Fix up entry points. */ for (i = 0; i < RUNTIME_NF_ARP_NUMHOOKS; i++) { /* In practice, we never delete up to a hook entry, since the built-in chains are always first, so these two are never equal */ if ((*handle)->info.hook_entry[i] >= offset + rules_size) (*handle)->info.hook_entry[i] -= rules_size; else if ((*handle)->info.hook_entry[i] > offset) { fprintf(stderr, "ERROR: Deleting entry %u %u %u\n", i, (*handle)->info.hook_entry[i], offset); abort(); } /* Underflow points to policy (terminal) rule in built-in, so sequality is valid here (when deleting the last rule). */ if ((*handle)->info.underflow[i] >= offset + rules_size) (*handle)->info.underflow[i] -= rules_size; else if ((*handle)->info.underflow[i] > offset) { fprintf(stderr, "ERROR: Deleting uflow %u %u %u\n", i, (*handle)->info.underflow[i], offset); abort(); } } /* Move the rules down. */ memmove((char *)(*handle)->entries.entrytable + offset, (char *)(*handle)->entries.entrytable + offset + rules_size, (*handle)->entries.size - (offset + rules_size)); /* Move the counter map down. */ memmove(&(*handle)->counter_map[num_rules_offset], &(*handle)->counter_map[num_rules_offset + num_rules], sizeof(struct counter_map) * ((*handle)->new_number - (num_rules + num_rules_offset))); /* Fix numbers */ (*handle)->new_number -= num_rules; (*handle)->entries.size -= rules_size; return set_verdict(offset, -(int)rules_size, handle); } static int standard_map(STRUCT_ENTRY *e, int verdict) { STRUCT_STANDARD_TARGET *t; t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e); if (t->target.u.target_size != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) { errno = EINVAL; return 0; } /* memset for memcmp convenience on delete/replace */ memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN); strcpy(t->target.u.user.name, STANDARD_TARGET); t->verdict = verdict; return 1; } static int map_target(const TC_HANDLE_T handle, STRUCT_ENTRY *e, unsigned int offset, STRUCT_ENTRY_TARGET *old) { STRUCT_ENTRY_TARGET *t = GET_TARGET(e); /* Save old target (except data, which we don't change, except for standard case, where we don't care). */ *old = *t; /* Maybe it's empty (=> fall through) */ if (strcmp(t->u.user.name, "") == 0) return standard_map(e, offset + e->next_offset); /* Maybe it's a standard target name... */ else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0) return standard_map(e, -NF_ACCEPT - 1); else if (strcmp(t->u.user.name, LABEL_DROP) == 0) return standard_map(e, -NF_DROP - 1); else if (strcmp(t->u.user.name, LABEL_QUEUE) == 0) return standard_map(e, -NF_QUEUE - 1); else if (strcmp(t->u.user.name, LABEL_RETURN) == 0) return standard_map(e, RETURN); else if (TC_BUILTIN(t->u.user.name, handle)) { /* Can't jump to builtins. */ errno = EINVAL; return 0; } else { /* Maybe it's an existing chain name. */ struct chain_cache *c; c = find_label(t->u.user.name, handle); if (c) return standard_map(e, entry2offset(handle, c->start)); } /* Must be a module? If not, kernel will reject... */ /* memset to all 0 for your memcmp convenience. */ memset(t->u.user.name + strlen(t->u.user.name), 0, FUNCTION_MAXNAMELEN - 1 - strlen(t->u.user.name)); return 1; } static void unmap_target(STRUCT_ENTRY *e, STRUCT_ENTRY_TARGET *old) { STRUCT_ENTRY_TARGET *t = GET_TARGET(e); /* Save old target (except data, which we don't change, except for standard case, where we don't care). */ *t = *old; } /* Insert the entry `fw' in chain `chain' into position `rulenum'. */ int TC_INSERT_ENTRY(const ARPT_CHAINLABEL chain, const STRUCT_ENTRY *e, unsigned int rulenum, TC_HANDLE_T *handle) { unsigned int chainindex, offset; STRUCT_ENTRY_TARGET old; struct chain_cache *c; STRUCT_ENTRY *tmp; int ret; arptc_fn = TC_INSERT_ENTRY; if (!(c = find_label(chain, *handle))) { errno = ENOENT; return 0; } chainindex = entry2index(*handle, c->start); tmp = index2entry(*handle, chainindex + rulenum); if (!tmp || tmp > c->end) { errno = E2BIG; return 0; } offset = index2offset(*handle, chainindex + rulenum); /* Mapping target actually alters entry, but that's transparent to the caller. */ if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old)) return 0; ret = insert_rules(1, e->next_offset, e, offset, chainindex + rulenum, rulenum == 0, handle); unmap_target((STRUCT_ENTRY *)e, &old); return ret; } /* Atomically replace rule `rulenum' in `chain' with `fw'. */ int TC_REPLACE_ENTRY(const ARPT_CHAINLABEL chain, const STRUCT_ENTRY *e, unsigned int rulenum, TC_HANDLE_T *handle) { unsigned int chainindex, offset; STRUCT_ENTRY_TARGET old; struct chain_cache *c; STRUCT_ENTRY *tmp; int ret; arptc_fn = TC_REPLACE_ENTRY; if (!(c = find_label(chain, *handle))) { errno = ENOENT; return 0; } chainindex = entry2index(*handle, c->start); tmp = index2entry(*handle, chainindex + rulenum); if (!tmp || tmp >= c->end) { errno = E2BIG; return 0; } offset = index2offset(*handle, chainindex + rulenum); /* Replace = delete and insert. */ if (!delete_rules(1, get_entry(*handle, offset)->next_offset, offset, chainindex + rulenum, handle)) return 0; if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old)) return 0; ret = insert_rules(1, e->next_offset, e, offset, chainindex + rulenum, 1, handle); unmap_target((STRUCT_ENTRY *)e, &old); return ret; } /* Append entry `fw' to chain `chain'. Equivalent to insert with rulenum = length of chain. */ int TC_APPEND_ENTRY(const ARPT_CHAINLABEL chain, const STRUCT_ENTRY *e, TC_HANDLE_T *handle) { struct chain_cache *c; STRUCT_ENTRY_TARGET old; int ret; arptc_fn = TC_APPEND_ENTRY; if (!(c = find_label(chain, *handle))) { errno = ENOENT; return 0; } if (!map_target(*handle, (STRUCT_ENTRY *)e, entry2offset(*handle, c->end), &old)) return 0; ret = insert_rules(1, e->next_offset, e, entry2offset(*handle, c->end), entry2index(*handle, c->end), 0, handle); unmap_target((STRUCT_ENTRY *)e, &old); return ret; } /* static inline int match_different(const STRUCT_ENTRY_MATCH *a, const unsigned char *a_elems, const unsigned char *b_elems, unsigned char **maskptr) { const STRUCT_ENTRY_MATCH *b; unsigned int i; */ /* Offset of b is the same as a. */ /* b = (void *)b_elems + ((unsigned char *)a - a_elems); if (a->u.match_size != b->u.match_size) return 1; if (strcmp(a->u.user.name, b->u.user.name) != 0) return 1; *maskptr += ALIGN(sizeof(*a)); for (i = 0; i < a->u.match_size - ALIGN(sizeof(*a)); i++) if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0) return 1; *maskptr += i; return 0; } */ static inline int target_different(const unsigned char *a_targdata, const unsigned char *b_targdata, unsigned int tdatasize, const unsigned char *mask) { unsigned int i; for (i = 0; i < tdatasize; i++) if (((a_targdata[i] ^ b_targdata[i]) & mask[i]) != 0) return 1; return 0; } static int is_same(const STRUCT_ENTRY *a, const STRUCT_ENTRY *b, unsigned char *matchmask); /* Delete the first rule in `chain' which matches `fw'. */ int TC_DELETE_ENTRY(const ARPT_CHAINLABEL chain, const STRUCT_ENTRY *origfw, unsigned char *matchmask, TC_HANDLE_T *handle) { unsigned int offset; struct chain_cache *c; STRUCT_ENTRY *e, *fw; arptc_fn = TC_DELETE_ENTRY; if (!(c = find_label(chain, *handle))) { errno = ENOENT; return 0; } fw = malloc(origfw->next_offset); if (fw == NULL) { errno = ENOMEM; return 0; } for (offset = entry2offset(*handle, c->start); offset < entry2offset(*handle, c->end); offset += e->next_offset) { STRUCT_ENTRY_TARGET discard; memcpy(fw, origfw, origfw->next_offset); /* FIXME: handle this in is_same --RR */ if (!map_target(*handle, fw, offset, &discard)) { free(fw); return 0; } e = get_entry(*handle, offset); #if 0 printf("Deleting:\n"); dump_entry(newe); #endif if (is_same(e, fw, matchmask)) { int ret; ret = delete_rules(1, e->next_offset, offset, entry2index(*handle, e), handle); free(fw); return ret; } } free(fw); errno = ENOENT; return 0; } /* Delete the rule in position `rulenum' in `chain'. */ int TC_DELETE_NUM_ENTRY(const ARPT_CHAINLABEL chain, unsigned int rulenum, TC_HANDLE_T *handle) { unsigned int index; int ret; STRUCT_ENTRY *e; struct chain_cache *c; arptc_fn = TC_DELETE_NUM_ENTRY; if (!(c = find_label(chain, *handle))) { errno = ENOENT; return 0; } index = entry2index(*handle, c->start) + rulenum; if (index >= entry2index(*handle, c->end)) { errno = E2BIG; return 0; } e = index2entry(*handle, index); if (e == NULL) { errno = EINVAL; return 0; } ret = delete_rules(1, e->next_offset, entry2offset(*handle, e), index, handle); return ret; } /* Check the packet `fw' on chain `chain'. Returns the verdict, or NULL and sets errno. */ const char * TC_CHECK_PACKET(const ARPT_CHAINLABEL chain, STRUCT_ENTRY *entry, TC_HANDLE_T *handle) { errno = ENOSYS; return NULL; } /* Flushes the entries in the given chain (ie. empties chain). */ int TC_FLUSH_ENTRIES(const ARPT_CHAINLABEL chain, TC_HANDLE_T *handle) { unsigned int startindex, endindex; struct chain_cache *c; int ret; arptc_fn = TC_FLUSH_ENTRIES; if (!(c = find_label(chain, *handle))) { errno = ENOENT; return 0; } startindex = entry2index(*handle, c->start); endindex = entry2index(*handle, c->end); ret = delete_rules(endindex - startindex, (char *)c->end - (char *)c->start, entry2offset(*handle, c->start), startindex, handle); return ret; } /* Zeroes the counters in a chain. */ int TC_ZERO_ENTRIES(const ARPT_CHAINLABEL chain, TC_HANDLE_T *handle) { unsigned int i, end; struct chain_cache *c; if (!(c = find_label(chain, *handle))) { errno = ENOENT; return 0; } i = entry2index(*handle, c->start); end = entry2index(*handle, c->end); for (; i <= end; i++) { if ((*handle)->counter_map[i].maptype ==COUNTER_MAP_NORMAL_MAP) (*handle)->counter_map[i].maptype = COUNTER_MAP_ZEROED; } set_changed(*handle); return 1; } STRUCT_COUNTERS * TC_READ_COUNTER(const ARPT_CHAINLABEL chain, unsigned int rulenum, TC_HANDLE_T *handle) { STRUCT_ENTRY *e; struct chain_cache *c; unsigned int chainindex, end; arptc_fn = TC_READ_COUNTER; CHECK(*handle); if (!(c = find_label(chain, *handle))) { errno = ENOENT; return NULL; } chainindex = entry2index(*handle, c->start); end = entry2index(*handle, c->end); if (chainindex + rulenum > end) { errno = E2BIG; return NULL; } e = index2entry(*handle, chainindex + rulenum); return &e->counters; } int TC_ZERO_COUNTER(const ARPT_CHAINLABEL chain, unsigned int rulenum, TC_HANDLE_T *handle) { struct chain_cache *c; unsigned int chainindex, end; arptc_fn = TC_ZERO_COUNTER; CHECK(*handle); if (!(c = find_label(chain, *handle))) { errno = ENOENT; return 0; } chainindex = entry2index(*handle, c->start); end = entry2index(*handle, c->end); if (chainindex + rulenum > end) { errno = E2BIG; return 0; } if ((*handle)->counter_map[chainindex + rulenum].maptype == COUNTER_MAP_NORMAL_MAP) { (*handle)->counter_map[chainindex + rulenum].maptype = COUNTER_MAP_ZEROED; } set_changed(*handle); return 1; } int TC_SET_COUNTER(const ARPT_CHAINLABEL chain, unsigned int rulenum, STRUCT_COUNTERS *counters, TC_HANDLE_T *handle) { STRUCT_ENTRY *e; struct chain_cache *c; unsigned int chainindex, end; arptc_fn = TC_SET_COUNTER; CHECK(*handle); if (!(c = find_label(chain, *handle))) { errno = ENOENT; return 0; } chainindex = entry2index(*handle, c->start); end = entry2index(*handle, c->end); if (chainindex + rulenum > end) { errno = E2BIG; return 0; } e = index2entry(*handle, chainindex + rulenum); (*handle)->counter_map[chainindex + rulenum].maptype = COUNTER_MAP_SET; memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS)); set_changed(*handle); return 1; } /* Creates a new chain. */ /* To create a chain, create two rules: error node and unconditional * return. */ int TC_CREATE_CHAIN(const ARPT_CHAINLABEL chain, TC_HANDLE_T *handle) { int ret; struct { STRUCT_ENTRY head; struct arpt_error_target name; STRUCT_ENTRY ret; STRUCT_STANDARD_TARGET target; } newc; arptc_fn = TC_CREATE_CHAIN; /* find_label doesn't cover built-in targets: DROP, ACCEPT, QUEUE, RETURN. */ if (find_label(chain, *handle) || strcmp(chain, LABEL_DROP) == 0 || strcmp(chain, LABEL_ACCEPT) == 0 || strcmp(chain, LABEL_QUEUE) == 0 || strcmp(chain, LABEL_RETURN) == 0) { errno = EEXIST; return 0; } if (strlen(chain)+1 > sizeof(ARPT_CHAINLABEL)) { errno = EINVAL; return 0; } memset(&newc, 0, sizeof(newc)); newc.head.target_offset = sizeof(STRUCT_ENTRY); newc.head.next_offset = sizeof(STRUCT_ENTRY) + ALIGN(sizeof(struct arpt_error_target)); strcpy(newc.name.target.u.user.name, ERROR_TARGET); newc.name.target.u.target_size = ALIGN(sizeof(struct arpt_error_target)); strcpy(newc.name.errorname, chain); newc.ret.target_offset = sizeof(STRUCT_ENTRY); newc.ret.next_offset = sizeof(STRUCT_ENTRY) + ALIGN(sizeof(STRUCT_STANDARD_TARGET)); strcpy(newc.target.target.u.user.name, STANDARD_TARGET); newc.target.target.u.target_size = ALIGN(sizeof(STRUCT_STANDARD_TARGET)); newc.target.verdict = RETURN; /* Add just before terminal entry */ ret = insert_rules(2, sizeof(newc), &newc.head, index2offset(*handle, (*handle)->new_number - 1), (*handle)->new_number - 1, 0, handle); return ret; } static int count_ref(STRUCT_ENTRY *e, unsigned int offset, unsigned int *ref) { STRUCT_STANDARD_TARGET *t; if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) == 0) { t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e); if (t->verdict == offset) (*ref)++; } return 0; } /* Get the number of references to this chain. */ int TC_GET_REFERENCES(unsigned int *ref, const ARPT_CHAINLABEL chain, TC_HANDLE_T *handle) { struct chain_cache *c; if (!(c = find_label(chain, *handle))) { errno = ENOENT; return 0; } *ref = 0; ENTRY_ITERATE((*handle)->entries.entrytable, (*handle)->entries.size, count_ref, entry2offset(*handle, c->start), ref); return 1; } /* Deletes a chain. */ int TC_DELETE_CHAIN(const ARPT_CHAINLABEL chain, TC_HANDLE_T *handle) { unsigned int labelidx, labeloff; unsigned int references; struct chain_cache *c; int ret; if (!TC_GET_REFERENCES(&references, chain, handle)) return 0; arptc_fn = TC_DELETE_CHAIN; if (TC_BUILTIN(chain, *handle)) { errno = EINVAL; return 0; } if (references > 0) { errno = EMLINK; return 0; } if (!(c = find_label(chain, *handle))) { errno = ENOENT; return 0; } if ((void *)c->start != c->end) { errno = ENOTEMPTY; return 0; } /* Need label index: preceeds chain start */ labelidx = entry2index(*handle, c->start) - 1; labeloff = index2offset(*handle, labelidx); ret = delete_rules(2, get_entry(*handle, labeloff)->next_offset + c->start->next_offset, labeloff, labelidx, handle); return ret; } /* Renames a chain. */ int TC_RENAME_CHAIN(const ARPT_CHAINLABEL oldname, const ARPT_CHAINLABEL newname, TC_HANDLE_T *handle) { unsigned int labeloff, labelidx; struct chain_cache *c; struct arpt_error_target *t; arptc_fn = TC_RENAME_CHAIN; /* find_label doesn't cover built-in targets: DROP, ACCEPT, QUEUE, RETURN. */ if (find_label(newname, *handle) || strcmp(newname, LABEL_DROP) == 0 || strcmp(newname, LABEL_ACCEPT) == 0 || strcmp(newname, LABEL_QUEUE) == 0 || strcmp(newname, LABEL_RETURN) == 0) { errno = EEXIST; return 0; } if (!(c = find_label(oldname, *handle)) || TC_BUILTIN(oldname, *handle)) { errno = ENOENT; return 0; } if (strlen(newname)+1 > sizeof(ARPT_CHAINLABEL)) { errno = EINVAL; return 0; } /* Need label index: preceeds chain start */ labelidx = entry2index(*handle, c->start) - 1; labeloff = index2offset(*handle, labelidx); t = (struct arpt_error_target *) GET_TARGET(get_entry(*handle, labeloff)); memset(t->errorname, 0, sizeof(t->errorname)); strcpy(t->errorname, newname); set_changed(*handle); return 1; } /* Sets the policy on a built-in chain. */ int TC_SET_POLICY(const ARPT_CHAINLABEL chain, const ARPT_CHAINLABEL policy, STRUCT_COUNTERS *counters, TC_HANDLE_T *handle) { unsigned int hook; unsigned int policyoff, ctrindex; STRUCT_ENTRY *e; STRUCT_STANDARD_TARGET *t; arptc_fn = TC_SET_POLICY; /* Figure out which chain. */ hook = TC_BUILTIN(chain, *handle); if (hook == 0) { errno = ENOENT; return 0; } else hook--; policyoff = get_chain_end(*handle, (*handle)->info.hook_entry[hook]); if (policyoff != (*handle)->info.underflow[hook]) { printf("ERROR: Policy for `%s' offset %u != underflow %u\n", chain, policyoff, (*handle)->info.underflow[hook]); return 0; } e = get_entry(*handle, policyoff); t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e); if (strcmp(policy, LABEL_ACCEPT) == 0) t->verdict = -NF_ACCEPT - 1; else if (strcmp(policy, LABEL_DROP) == 0) t->verdict = -NF_DROP - 1; else { errno = EINVAL; return 0; } ctrindex = entry2index(*handle, e); if (counters) { /* set byte and packet counters */ memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS)); (*handle)->counter_map[ctrindex].maptype = COUNTER_MAP_SET; } else { (*handle)->counter_map[ctrindex] = ((struct counter_map){ COUNTER_MAP_NOMAP, 0 }); } set_changed(*handle); return 1; } /* Without this, on gcc 2.7.2.3, we get: libarptc.c: In function `TC_COMMIT': libarptc.c:833: fixed or forbidden register was spilled. This may be due to a compiler bug or to impossible asm statements or clauses. */ static void subtract_counters(STRUCT_COUNTERS *answer, const STRUCT_COUNTERS *a, const STRUCT_COUNTERS *b) { answer->pcnt = a->pcnt - b->pcnt; answer->bcnt = a->bcnt - b->bcnt; } int TC_COMMIT(TC_HANDLE_T *handle) { /* Replace, then map back the counters. */ STRUCT_REPLACE *repl; STRUCT_COUNTERS_INFO *newcounters; unsigned int i; size_t counterlen = sizeof(STRUCT_COUNTERS_INFO) + sizeof(STRUCT_COUNTERS) * (*handle)->new_number; int sizeof_repl = sizeof(*repl); CHECK(*handle); #if 0 TC_DUMP_ENTRIES(*handle); #endif /* Don't commit if nothing changed. */ if (!(*handle)->changed) goto finished; /* allocate a bit more than needed for ease */ repl = malloc(2 * sizeof(*repl) + (*handle)->entries.size); if (!repl) { errno = ENOMEM; return 0; } /* These are the old counters we will get from kernel */ repl->counters = malloc(sizeof(STRUCT_COUNTERS) * (*handle)->info.num_entries); if (!repl->counters) { free(repl); errno = ENOMEM; return 0; } /* These are the counters we're going to put back, later. */ newcounters = malloc(counterlen); if (!newcounters) { free(repl->counters); free(repl); errno = ENOMEM; return 0; } strcpy(repl->name, (*handle)->info.name); repl->num_entries = (*handle)->new_number; repl->size = (*handle)->entries.size; memcpy(repl->hook_entry, (*handle)->info.hook_entry, sizeof(repl->hook_entry)); memcpy(repl->underflow, (*handle)->info.underflow, sizeof(repl->underflow)); repl->num_counters = (*handle)->info.num_entries; repl->valid_hooks = (*handle)->info.valid_hooks; memcpy(repl->entries, (*handle)->entries.entrytable, (*handle)->entries.size); if (RUNTIME_NF_ARP_NUMHOOKS == 2) { memmove(&(repl->underflow[2]), &(repl->underflow[3]), ((*handle)->entries.size) + sizeof(struct arpt_replace)); memmove(&(repl->hook_entry[2]), &(repl->hook_entry[3]), ((*handle)->entries.size) + sizeof(struct arpt_replace)); sizeof_repl -= 2 * sizeof(unsigned int); } if (setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl, sizeof_repl + (*handle)->entries.size) < 0) { free(repl->counters); free(repl); free(newcounters); return 0; } if (RUNTIME_NF_ARP_NUMHOOKS == 2) { memmove(&(repl->hook_entry[3]), &(repl->hook_entry[2]), ((*handle)->entries.size) + sizeof(struct arpt_replace)); memmove(&(repl->underflow[3]), &(repl->underflow[2]), ((*handle)->entries.size) + sizeof(struct arpt_replace)); } /* Put counters back. */ strcpy(newcounters->name, (*handle)->info.name); newcounters->num_counters = (*handle)->new_number; for (i = 0; i < (*handle)->new_number; i++) { unsigned int mappos = (*handle)->counter_map[i].mappos; switch ((*handle)->counter_map[i].maptype) { case COUNTER_MAP_NOMAP: newcounters->counters[i] = ((STRUCT_COUNTERS){ 0, 0 }); break; case COUNTER_MAP_NORMAL_MAP: /* Original read: X. * Atomic read on replacement: X + Y. * Currently in kernel: Z. * Want in kernel: X + Y + Z. * => Add in X + Y * => Add in replacement read. */ newcounters->counters[i] = repl->counters[mappos]; break; case COUNTER_MAP_ZEROED: /* Original read: X. * Atomic read on replacement: X + Y. * Currently in kernel: Z. * Want in kernel: Y + Z. * => Add in Y. * => Add in (replacement read - original read). */ subtract_counters(&newcounters->counters[i], &repl->counters[mappos], &index2entry(*handle, i)->counters); break; case COUNTER_MAP_SET: /* Want to set counter (iptables-restore) */ memcpy(&newcounters->counters[i], &index2entry(*handle, i)->counters, sizeof(STRUCT_COUNTERS)); break; } } #ifdef KERNEL_64_USERSPACE_32 { /* Kernel will think that pointer should be 64-bits, and get padding. So we accomodate here (assumption: alignment of `counters' is on 64-bit boundary). */ uint64_t *kernptr = (uint64_t *)&newcounters->counters; if ((unsigned long)&newcounters->counters % 8 != 0) { fprintf(stderr, "counters alignment incorrect! Mail rusty!\n"); abort(); } *kernptr = newcounters->counters; } #endif /* KERNEL_64_USERSPACE_32 */ if (setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS, newcounters, counterlen) < 0) { free(repl->counters); free(repl); free(newcounters); return 0; } free(repl->counters); free(repl); free(newcounters); finished: if ((*handle)->cache_chain_heads) free((*handle)->cache_chain_heads); free(*handle); *handle = NULL; return 1; } /* Get raw socket. */ int TC_GET_RAW_SOCKET() { return sockfd; } /* Translates errno numbers into more human-readable form than strerror. */ const char * TC_STRERROR(int err) { unsigned int i; struct table_struct { void *fn; int err; const char *message; } table [] = { { TC_INIT, EPERM, "Permission denied (you must be root)" }, { TC_INIT, EINVAL, "Module is wrong version" }, { TC_INIT, ENOENT, "Table does not exist (do you need to insmod?)" }, { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" }, { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" }, { TC_DELETE_CHAIN, EMLINK, "Can't delete chain with references left" }, { TC_CREATE_CHAIN, EEXIST, "Chain already exists" }, { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" }, { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" }, { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" }, { TC_READ_COUNTER, E2BIG, "Index of counter too big" }, { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" }, { TC_INSERT_ENTRY, ELOOP, "Loop found in table" }, { TC_INSERT_ENTRY, EINVAL, "Target problem" }, /* EINVAL for CHECK probably means bad interface. */ { TC_CHECK_PACKET, EINVAL, "Bad arguments (does that interface exist?)" }, { TC_CHECK_PACKET, ENOSYS, "Checking will most likely never get implemented" }, /* ENOENT for DELETE probably means no matching rule */ { TC_DELETE_ENTRY, ENOENT, "Bad rule (does a matching rule exist in that chain?)" }, { TC_SET_POLICY, ENOENT, "Bad built-in chain name" }, { TC_SET_POLICY, EINVAL, "Bad policy name" }, { NULL, 0, "Incompatible with this kernel" }, { NULL, ENOPROTOOPT, "arptables who? (do you need to insmod?)" }, { NULL, ENOSYS, "Will be implemented real soon. I promise ;)" }, { NULL, ENOMEM, "Memory allocation problem" }, { NULL, ENOENT, "No chain/target/match by that name" }, }; for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) { if ((!table[i].fn || table[i].fn == arptc_fn) && table[i].err == err) return table[i].message; } return strerror(err); } arptables-0.0.5/libarptc/libarptc.c0000644000175000017500000003664213571215622016230 0ustar pablopablo/* Library which manipulates firewall rules. Version 0.1. */ /* Architecture of firewall rules is as follows: * * Chains go INPUT, FORWARD, OUTPUT then user chains. * Each user chain starts with an ERROR node. * Every chain ends with an unconditional jump: a RETURN for user chains, * and a POLICY for built-ins. */ /* (C)1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See COPYING for details). */ #include #include #include #include #include #include #include #ifdef DEBUG_CONNTRACK #define inline #endif #include "libarptc/libarptc.h" #define IP_VERSION 4 #define IP_OFFSET 0x1FFF #define STRUCT_ENTRY_TARGET struct arpt_entry_target #define STRUCT_ENTRY struct arpt_entry #define STRUCT_ENTRY_MATCH struct arpt_entry_match #define STRUCT_GETINFO struct arpt_getinfo #define STRUCT_GET_ENTRIES struct arpt_get_entries #define STRUCT_COUNTERS struct arpt_counters #define STRUCT_COUNTERS_INFO struct arpt_counters_info #define STRUCT_STANDARD_TARGET struct arpt_standard_target #define STRUCT_REPLACE struct arpt_replace #define STRUCT_TC_HANDLE struct arptc_handle #define TC_HANDLE_T arptc_handle_t #define ENTRY_ITERATE ARPT_ENTRY_ITERATE #define TABLE_MAXNAMELEN ARPT_TABLE_MAXNAMELEN #define FUNCTION_MAXNAMELEN ARPT_FUNCTION_MAXNAMELEN #define GET_TARGET arpt_get_target #define ERROR_TARGET ARPT_ERROR_TARGET #define ARPT_CHAINLABEL arpt_chainlabel #define TC_DUMP_ENTRIES dump_entries #define TC_IS_CHAIN arptc_is_chain #define TC_FIRST_CHAIN arptc_first_chain #define TC_NEXT_CHAIN arptc_next_chain #define TC_FIRST_RULE arptc_first_rule #define TC_NEXT_RULE arptc_next_rule #define TC_GET_TARGET arptc_get_target #define TC_BUILTIN arptc_builtin #define TC_GET_POLICY arptc_get_policy #define TC_INSERT_ENTRY arptc_insert_entry #define TC_REPLACE_ENTRY arptc_replace_entry #define TC_APPEND_ENTRY arptc_append_entry #define TC_DELETE_ENTRY arptc_delete_entry #define TC_DELETE_NUM_ENTRY arptc_delete_num_entry #define TC_CHECK_PACKET arptc_check_packet #define TC_FLUSH_ENTRIES arptc_flush_entries #define TC_ZERO_ENTRIES arptc_zero_entries #define TC_READ_COUNTER arptc_read_counter #define TC_ZERO_COUNTER arptc_zero_counter #define TC_SET_COUNTER arptc_set_counter #define TC_CREATE_CHAIN arptc_create_chain #define TC_GET_REFERENCES arptc_get_references #define TC_DELETE_CHAIN arptc_delete_chain #define TC_RENAME_CHAIN arptc_rename_chain #define TC_SET_POLICY arptc_set_policy #define TC_GET_RAW_SOCKET arptc_get_raw_socket #define TC_INIT arptc_init #define TC_COMMIT arptc_commit #define TC_STRERROR arptc_strerror #define TC_AF AF_INET #define TC_IPPROTO IPPROTO_IP #define SO_SET_REPLACE ARPT_SO_SET_REPLACE #define SO_SET_ADD_COUNTERS ARPT_SO_SET_ADD_COUNTERS #define SO_GET_INFO ARPT_SO_GET_INFO #define SO_GET_ENTRIES ARPT_SO_GET_ENTRIES #define SO_GET_VERSION ARPT_SO_GET_VERSION #define STANDARD_TARGET ARPT_STANDARD_TARGET #define LABEL_RETURN ARPTC_LABEL_RETURN #define LABEL_ACCEPT ARPTC_LABEL_ACCEPT #define LABEL_DROP ARPTC_LABEL_DROP #define LABEL_QUEUE ARPTC_LABEL_QUEUE #define ALIGN ARPT_ALIGN #define RETURN ARPT_RETURN #include "libarptc_incl.c" #define IP_PARTS_NATIVE(n) \ (unsigned int)((n)>>24)&0xFF, \ (unsigned int)((n)>>16)&0xFF, \ (unsigned int)((n)>>8)&0xFF, \ (unsigned int)((n)&0xFF) #define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n)) int dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle) { size_t i; STRUCT_ENTRY_TARGET *t; printf("Entry %u (%lu):\n", entry2index(handle, e), entry2offset(handle, e)); printf("SRC IP: %u.%u.%u.%u/%u.%u.%u.%u\n", IP_PARTS(e->arp.src.s_addr),IP_PARTS(e->arp.smsk.s_addr)); printf("DST IP: %u.%u.%u.%u/%u.%u.%u.%u\n", IP_PARTS(e->arp.tgt.s_addr),IP_PARTS(e->arp.tmsk.s_addr)); printf("Interface: `%s'/", e->arp.iniface); for (i = 0; i < IFNAMSIZ; i++) printf("%c", e->arp.iniface_mask[i] ? 'X' : '.'); printf("to `%s'/", e->arp.outiface); for (i = 0; i < IFNAMSIZ; i++) printf("%c", e->arp.outiface_mask[i] ? 'X' : '.'); printf("Flags: %02X\n", e->arp.flags); printf("Invflags: %02X\n", e->arp.invflags); printf("Counters: %"PRIu64" packets, %"PRIu64" bytes\n", (uint64_t)e->counters.pcnt, (uint64_t)e->counters.bcnt); /* printf("Cache: %08X ", e->nfcache); if (e->nfcache & NFC_ALTERED) printf("ALTERED "); if (e->nfcache & NFC_UNKNOWN) printf("UNKNOWN "); if (e->nfcache & NFC_IP_SRC) printf("IP_SRC "); if (e->nfcache & NFC_IP_DST) printf("IP_DST "); if (e->nfcache & NFC_IP_IF_IN) printf("IP_IF_IN "); if (e->nfcache & NFC_IP_IF_OUT) printf("IP_IF_OUT "); if (e->nfcache & NFC_IP_TOS) printf("IP_TOS "); if (e->nfcache & NFC_IP_PROTO) printf("IP_PROTO "); if (e->nfcache & NFC_IP_OPTIONS) printf("IP_OPTIONS "); if (e->nfcache & NFC_IP_TCPFLAGS) printf("IP_TCPFLAGS "); if (e->nfcache & NFC_IP_SRC_PT) printf("IP_SRC_PT "); if (e->nfcache & NFC_IP_DST_PT) printf("IP_DST_PT "); if (e->nfcache & NFC_IP_PROTO_UNKNOWN) printf("IP_PROTO_UNKNOWN "); */ printf("\n"); /* ARPT_MATCH_ITERATE(e, print_match); */ t = GET_TARGET(e); printf("Target name: `%s' [%u]\n", t->u.user.name, t->u.target_size); if (strcmp(t->u.user.name, STANDARD_TARGET) == 0) { const unsigned char *data = t->data; const int pos = *(const int *)data; if (pos < 0) printf("verdict=%s\n", pos == -NF_ACCEPT-1 ? "NF_ACCEPT" : pos == -NF_DROP-1 ? "NF_DROP" : pos == -NF_QUEUE-1 ? "NF_QUEUE" : pos == RETURN ? "RETURN" : "UNKNOWN"); else printf("verdict=%u\n", pos); } else if (strcmp(t->u.user.name, ARPT_ERROR_TARGET) == 0) printf("error=`%s'\n", t->data); printf("\n"); return 0; } static int is_same(const STRUCT_ENTRY *a, const STRUCT_ENTRY *b, unsigned char *matchmask) { unsigned int i; STRUCT_ENTRY_TARGET *ta, *tb; unsigned char *mptr; /* Always compare head structures: ignore mask here. */ if (a->arp.src.s_addr != b->arp.src.s_addr || a->arp.tgt.s_addr != b->arp.tgt.s_addr || a->arp.smsk.s_addr != b->arp.smsk.s_addr || a->arp.tmsk.s_addr != b->arp.tmsk.s_addr || a->arp.arhln != b->arp.arhln || a->arp.arhln_mask != b->arp.arhln_mask || a->arp.arpop != b->arp.arpop || a->arp.arpop_mask != b->arp.arpop_mask || a->arp.arhrd != b->arp.arhrd || a->arp.arhrd_mask != b->arp.arhrd_mask || a->arp.arpro != b->arp.arpro || a->arp.arpro_mask != b->arp.arpro_mask || a->arp.flags != b->arp.flags || a->arp.invflags != b->arp.invflags) return 0; for (i = 0; i < ARPT_DEV_ADDR_LEN_MAX; i++) { if (a->arp.src_devaddr.addr[i] != b->arp.src_devaddr.addr[i] || a->arp.src_devaddr.mask[i] != b->arp.src_devaddr.mask[i]) return 0; if (a->arp.tgt_devaddr.addr[i] != b->arp.tgt_devaddr.addr[i] || a->arp.tgt_devaddr.mask[i] != b->arp.tgt_devaddr.mask[i]) return 0; } for (i = 0; i < IFNAMSIZ; i++) { if (a->arp.iniface_mask[i] != b->arp.iniface_mask[i]) return 0; if ((a->arp.iniface[i] & a->arp.iniface_mask[i]) != (b->arp.iniface[i] & b->arp.iniface_mask[i])) return 0; if (a->arp.outiface_mask[i] != b->arp.outiface_mask[i]) return 0; if ((a->arp.outiface[i] & a->arp.outiface_mask[i]) != (b->arp.outiface[i] & b->arp.outiface_mask[i])) return 0; } if (/* a->nfcache != b->nfcache || */a->target_offset != b->target_offset || a->next_offset != b->next_offset) return 0; mptr = matchmask + sizeof(STRUCT_ENTRY); /* if (ARPT_MATCH_ITERATE(a, match_different, a->elems, b->elems, &mptr)) return 0; */ ta = GET_TARGET((STRUCT_ENTRY *)a); tb = GET_TARGET((STRUCT_ENTRY *)b); if (ta->u.target_size != tb->u.target_size) return 0; if (strcmp(ta->u.user.name, tb->u.user.name) != 0) return 0; mptr += sizeof(*ta); if (target_different(ta->data, tb->data, ta->u.target_size - sizeof(*ta), mptr)) return 0; return 1; } /***************************** DEBUGGING ********************************/ static inline int unconditional(const struct arpt_arp *arp) { unsigned int i; for (i = 0; i < sizeof(*arp) / sizeof(uint32_t); i++) if (((uint32_t *)arp)[i]) return 0; return 1; } /* static inline int check_match(const STRUCT_ENTRY_MATCH *m, unsigned int *off) { assert(m->u.match_size >= sizeof(STRUCT_ENTRY_MATCH)); assert(ALIGN(m->u.match_size) == m->u.match_size); (*off) += m->u.match_size; return 0; } */ static inline int check_entry(const STRUCT_ENTRY *e, unsigned int *i, unsigned int *off, unsigned int user_offset, int *was_return, TC_HANDLE_T h) { unsigned int toff; STRUCT_STANDARD_TARGET *t; assert(e->target_offset >= sizeof(STRUCT_ENTRY)); assert(e->next_offset >= e->target_offset + sizeof(STRUCT_ENTRY_TARGET)); toff = sizeof(STRUCT_ENTRY); /* ARPT_MATCH_ITERATE(e, check_match, &toff); */ assert(toff == e->target_offset); t = (STRUCT_STANDARD_TARGET *) GET_TARGET((STRUCT_ENTRY *)e); /* next_offset will have to be multiple of entry alignment. */ assert(e->next_offset == ALIGN(e->next_offset)); assert(e->target_offset == ALIGN(e->target_offset)); assert(t->target.u.target_size == ALIGN(t->target.u.target_size)); assert(!TC_IS_CHAIN(t->target.u.user.name, h)); if (strcmp(t->target.u.user.name, STANDARD_TARGET) == 0) { assert(t->target.u.target_size == ALIGN(sizeof(STRUCT_STANDARD_TARGET))); assert(t->verdict == -NF_DROP-1 || t->verdict == -NF_ACCEPT-1 || t->verdict == RETURN || t->verdict < (int)h->entries.size); if (t->verdict >= 0) { STRUCT_ENTRY *te = get_entry(h, t->verdict); int idx; idx = entry2index(h, te); assert(strcmp(GET_TARGET(te)->u.user.name, ARPT_ERROR_TARGET) != 0); assert(te != e); /* Prior node must be error node, or this node. */ assert(t->verdict == entry2offset(h, e)+e->next_offset || strcmp(GET_TARGET(index2entry(h, idx-1)) ->u.user.name, ARPT_ERROR_TARGET) == 0); } if (t->verdict == RETURN && unconditional(&e->arp) && e->target_offset == sizeof(*e)) *was_return = 1; else *was_return = 0; } else if (strcmp(t->target.u.user.name, ARPT_ERROR_TARGET) == 0) { assert(t->target.u.target_size == ALIGN(sizeof(struct arpt_error_target))); /* If this is in user area, previous must have been return */ if (*off > user_offset) assert(*was_return); *was_return = 0; } else *was_return = 0; if (*off == user_offset) assert(strcmp(t->target.u.user.name, ARPT_ERROR_TARGET) == 0); (*off) += e->next_offset; (*i)++; return 0; } #ifdef ARPTC_DEBUG /* Do every conceivable sanity check on the handle */ static void do_check(TC_HANDLE_T h, unsigned int line) { unsigned int i, n; unsigned int user_offset; /* Offset of first user chain */ int was_return; assert(h->changed == 0 || h->changed == 1); if (strcmp(h->info.name, "filter") == 0) { assert(h->info.valid_hooks == (1 << NF_IP_LOCAL_IN | 1 << NF_IP_FORWARD | 1 << NF_IP_LOCAL_OUT)); /* Hooks should be first three */ assert(h->info.hook_entry[NF_IP_LOCAL_IN] == 0); n = get_chain_end(h, 0); n += get_entry(h, n)->next_offset; assert(h->info.hook_entry[NF_IP_FORWARD] == n); n = get_chain_end(h, n); n += get_entry(h, n)->next_offset; assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n); user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT]; } else if (strcmp(h->info.name, "nat") == 0) { assert((h->info.valid_hooks == (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_POST_ROUTING | 1 << NF_IP_LOCAL_OUT)) || (h->info.valid_hooks == (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_LOCAL_IN | 1 << NF_IP_POST_ROUTING | 1 << NF_IP_LOCAL_OUT))); assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0); n = get_chain_end(h, 0); n += get_entry(h, n)->next_offset; assert(h->info.hook_entry[NF_IP_POST_ROUTING] == n); n = get_chain_end(h, n); n += get_entry(h, n)->next_offset; assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n); user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT]; if (h->info.valid_hooks & (1 << NF_IP_LOCAL_IN)) { n = get_chain_end(h, n); n += get_entry(h, n)->next_offset; assert(h->info.hook_entry[NF_IP_LOCAL_IN] == n); user_offset = h->info.hook_entry[NF_IP_LOCAL_IN]; } } else if (strcmp(h->info.name, "mangle") == 0) { /* This code is getting ugly because linux < 2.4.18-pre6 had * two mangle hooks, linux >= 2.4.18-pre6 has five mangle hooks * */ assert((h->info.valid_hooks == (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_LOCAL_OUT)) || (h->info.valid_hooks == (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_LOCAL_IN | 1 << NF_IP_FORWARD | 1 << NF_IP_LOCAL_OUT | 1 << NF_IP_POST_ROUTING))); /* Hooks should be first five */ assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0); n = get_chain_end(h, 0); if (h->info.valid_hooks & (1 << NF_IP_LOCAL_IN)) { n += get_entry(h, n)->next_offset; assert(h->info.hook_entry[NF_IP_LOCAL_IN] == n); n = get_chain_end(h, n); } if (h->info.valid_hooks & (1 << NF_IP_FORWARD)) { n += get_entry(h, n)->next_offset; assert(h->info.hook_entry[NF_IP_FORWARD] == n); n = get_chain_end(h, n); } n += get_entry(h, n)->next_offset; assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n); user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT]; if (h->info.valid_hooks & (1 << NF_IP_POST_ROUTING)) { n = get_chain_end(h, n); n += get_entry(h, n)->next_offset; assert(h->info.hook_entry[NF_IP_POST_ROUTING] == n); user_offset = h->info.hook_entry[NF_IP_POST_ROUTING]; } #ifdef NF_IP_DROPPING } else if (strcmp(h->info.name, "drop") == 0) { assert(h->info.valid_hooks == (1 << NF_IP_DROPPING)); /* Hook should be first */ assert(h->info.hook_entry[NF_IP_DROPPING] == 0); user_offset = 0; #endif } else { fprintf(stderr, "Unknown table `%s'\n", h->info.name); abort(); } /* User chain == end of last builtin + policy entry */ user_offset = get_chain_end(h, user_offset); user_offset += get_entry(h, user_offset)->next_offset; /* Overflows should be end of entry chains, and unconditional policy nodes. */ for (i = 0; i < RUNTIME_NF_ARP_NUMHOOKS; i++) { STRUCT_ENTRY *e; STRUCT_STANDARD_TARGET *t; if (!(h->info.valid_hooks & (1 << i))) continue; assert(h->info.underflow[i] == get_chain_end(h, h->info.hook_entry[i])); e = get_entry(h, get_chain_end(h, h->info.hook_entry[i])); assert(unconditional(&e->ip)); assert(e->target_offset == sizeof(*e)); t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e); assert(t->target.u.target_size == ALIGN(sizeof(*t))); assert(e->next_offset == sizeof(*e) + ALIGN(sizeof(*t))); assert(strcmp(t->target.u.user.name, STANDARD_TARGET)==0); assert(t->verdict == -NF_DROP-1 || t->verdict == -NF_ACCEPT-1); /* Hooks and underflows must be valid entries */ entry2index(h, get_entry(h, h->info.hook_entry[i])); entry2index(h, get_entry(h, h->info.underflow[i])); } assert(h->info.size >= h->info.num_entries * (sizeof(STRUCT_ENTRY) +sizeof(STRUCT_STANDARD_TARGET))); assert(h->entries.size >= (h->new_number * (sizeof(STRUCT_ENTRY) + sizeof(STRUCT_STANDARD_TARGET)))); assert(strcmp(h->info.name, h->entries.name) == 0); i = 0; n = 0; was_return = 0; /* Check all the entries. */ ENTRY_ITERATE(h->entries.entrytable, h->entries.size, check_entry, &i, &n, user_offset, &was_return, h); assert(i == h->new_number); assert(n == h->entries.size); /* Final entry must be error node */ assert(strcmp(GET_TARGET(index2entry(h, h->new_number-1)) ->u.user.name, ERROR_TARGET) == 0); } #endif /*ARPTC_DEBUG*/ arptables-0.0.5/include/0000755000175000017500000000000013571215622014074 5ustar pablopabloarptables-0.0.5/include/linux/0000755000175000017500000000000013571215622015233 5ustar pablopabloarptables-0.0.5/include/linux/netfilter_arp/0000755000175000017500000000000013571215622020071 5ustar pablopabloarptables-0.0.5/include/linux/netfilter_arp/arpt_mangle.h0000644000175000017500000000104313571215622022531 0ustar pablopablo#ifndef _ARPT_MANGLE_H #define _ARPT_MANGLE_H #include #define ARPT_MANGLE_ADDR_LEN_MAX sizeof(struct in_addr) struct arpt_mangle { char src_devaddr[ARPT_DEV_ADDR_LEN_MAX]; char tgt_devaddr[ARPT_DEV_ADDR_LEN_MAX]; union { struct in_addr src_ip; } u_s; union { struct in_addr tgt_ip; } u_t; u_int8_t flags; int target; }; #define ARPT_MANGLE_SDEV 0x01 #define ARPT_MANGLE_TDEV 0x02 #define ARPT_MANGLE_SIP 0x04 #define ARPT_MANGLE_TIP 0x08 #define ARPT_MANGLE_MASK 0x0f #endif /* _ARPT_MANGLE_H */ arptables-0.0.5/include/linux/netfilter_arp/arp_tables.h0000644000175000017500000001343213571215622022361 0ustar pablopablo/* * Format of an ARP firewall descriptor * * src, tgt, src_mask, tgt_mask, arpop, arpop_mask are always stored in * network byte order. * flags are stored in host byte order (of course). */ #ifndef _ARPTABLES_H #define _ARPTABLES_H #include #include #include #define ARPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN #define ARPT_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN #define arpt_entry_target xt_entry_target #define arpt_standard_target xt_standard_target #define arpt_error_target xt_error_target #define ARPT_CONTINUE XT_CONTINUE #define ARPT_RETURN XT_RETURN #define arpt_counters_info xt_counters_info #define arpt_counters xt_counters #define ARPT_STANDARD_TARGET XT_STANDARD_TARGET #define ARPT_ERROR_TARGET XT_ERROR_TARGET #define ARPT_ENTRY_ITERATE(entries, size, fn, args...) \ XT_ENTRY_ITERATE(struct arpt_entry, entries, size, fn, ## args) #define ARPT_DEV_ADDR_LEN_MAX 16 struct arpt_devaddr_info { char addr[ARPT_DEV_ADDR_LEN_MAX]; char mask[ARPT_DEV_ADDR_LEN_MAX]; }; /* Yes, Virginia, you have to zero the padding. */ struct arpt_arp { /* Source and target IP addr */ struct in_addr src, tgt; /* Mask for src and target IP addr */ struct in_addr smsk, tmsk; /* Device hw address length, src+target device addresses */ __u8 arhln, arhln_mask; struct arpt_devaddr_info src_devaddr; struct arpt_devaddr_info tgt_devaddr; /* ARP operation code. */ __be16 arpop, arpop_mask; /* ARP hardware address and protocol address format. */ __be16 arhrd, arhrd_mask; __be16 arpro, arpro_mask; /* The protocol address length is only accepted if it is 4 * so there is no use in offering a way to do filtering on it. */ char iniface[IFNAMSIZ], outiface[IFNAMSIZ]; unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ]; /* Flags word */ __u8 flags; /* Inverse flags */ __u16 invflags; }; /* Values for "flag" field in struct arpt_ip (general arp structure). * No flags defined yet. */ #define ARPT_F_MASK 0x00 /* All possible flag bits mask. */ /* Values for "inv" field in struct arpt_arp. */ #define ARPT_INV_VIA_IN 0x0001 /* Invert the sense of IN IFACE. */ #define ARPT_INV_VIA_OUT 0x0002 /* Invert the sense of OUT IFACE */ #define ARPT_INV_SRCIP 0x0004 /* Invert the sense of SRC IP. */ #define ARPT_INV_TGTIP 0x0008 /* Invert the sense of TGT IP. */ #define ARPT_INV_SRCDEVADDR 0x0010 /* Invert the sense of SRC DEV ADDR. */ #define ARPT_INV_TGTDEVADDR 0x0020 /* Invert the sense of TGT DEV ADDR. */ #define ARPT_INV_ARPOP 0x0040 /* Invert the sense of ARP OP. */ #define ARPT_INV_ARPHRD 0x0080 /* Invert the sense of ARP HRD. */ #define ARPT_INV_ARPPRO 0x0100 /* Invert the sense of ARP PRO. */ #define ARPT_INV_ARPHLN 0x0200 /* Invert the sense of ARP HLN. */ #define ARPT_INV_MASK 0x03FF /* All possible flag bits mask. */ /* This structure defines each of the firewall rules. Consists of 3 parts which are 1) general ARP header stuff 2) match specific stuff 3) the target to perform if the rule matches */ struct arpt_entry { struct arpt_arp arp; /* Size of arpt_entry + matches */ __u16 target_offset; /* Size of arpt_entry + matches + target */ __u16 next_offset; /* Back pointer */ unsigned int comefrom; /* Packet and byte counters. */ struct xt_counters counters; /* The matches (if any), then the target. */ unsigned char elems[0]; }; /* * New IP firewall options for [gs]etsockopt at the RAW IP level. * Unlike BSD Linux inherits IP options so you don't have to use a raw * socket for this. Instead we check rights in the calls. * * ATTENTION: check linux/in.h before adding new number here. */ #define ARPT_BASE_CTL 96 #define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL) #define ARPT_SO_SET_ADD_COUNTERS (ARPT_BASE_CTL + 1) #define ARPT_SO_SET_MAX ARPT_SO_SET_ADD_COUNTERS #define ARPT_SO_GET_INFO (ARPT_BASE_CTL) #define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1) /* #define ARPT_SO_GET_REVISION_MATCH (APRT_BASE_CTL + 2) */ #define ARPT_SO_GET_REVISION_TARGET (ARPT_BASE_CTL + 3) #define ARPT_SO_GET_MAX (ARPT_SO_GET_REVISION_TARGET) /* The argument to ARPT_SO_GET_INFO */ struct arpt_getinfo { /* Which table: caller fills this in. */ char name[XT_TABLE_MAXNAMELEN]; /* Kernel fills these in. */ /* Which hook entry points are valid: bitmask */ unsigned int valid_hooks; /* Hook entry points: one per netfilter hook. */ unsigned int hook_entry[NF_ARP_NUMHOOKS]; /* Underflow points. */ unsigned int underflow[NF_ARP_NUMHOOKS]; /* Number of entries */ unsigned int num_entries; /* Size of entries. */ unsigned int size; }; /* The argument to ARPT_SO_SET_REPLACE. */ struct arpt_replace { /* Which table. */ char name[XT_TABLE_MAXNAMELEN]; /* Which hook entry points are valid: bitmask. You can't change this. */ unsigned int valid_hooks; /* Number of entries */ unsigned int num_entries; /* Total size of new entries */ unsigned int size; /* Hook entry points. */ unsigned int hook_entry[NF_ARP_NUMHOOKS]; /* Underflow points. */ unsigned int underflow[NF_ARP_NUMHOOKS]; /* Information about old entries: */ /* Number of counters (must be equal to current number of entries). */ unsigned int num_counters; /* The old entries' counters. */ struct xt_counters *counters; /* The entries (hang off end: not really an array). */ struct arpt_entry entries[0]; }; /* The argument to ARPT_SO_GET_ENTRIES. */ struct arpt_get_entries { /* Which table: user fills this in. */ char name[XT_TABLE_MAXNAMELEN]; /* User fills this in: total entry size. */ unsigned int size; /* The entries. */ struct arpt_entry entrytable[0]; }; /* Helper functions */ static __inline__ struct xt_entry_target *arpt_get_target(struct arpt_entry *e) { return (void *)e + e->target_offset; } /* * Main firewall chains definitions and global var's definitions. */ #endif /* _ARPTABLES_H */ arptables-0.0.5/include/linux/netfilter_arp.h0000644000175000017500000000057413571215622020250 0ustar pablopablo#ifndef __LINUX_ARP_NETFILTER_H #define __LINUX_ARP_NETFILTER_H /* ARP-specific defines for netfilter. * (C)2002 Rusty Russell IBM -- This code is GPL. */ #include /* There is no PF_ARP. */ #define NF_ARP 0 /* ARP Hooks */ #define NF_ARP_IN 0 #define NF_ARP_OUT 1 #define NF_ARP_FORWARD 2 #define NF_ARP_NUMHOOKS 3 #endif /* __LINUX_ARP_NETFILTER_H */ arptables-0.0.5/include/linux/netfilter/0000755000175000017500000000000013571215622017227 5ustar pablopabloarptables-0.0.5/include/linux/netfilter/x_tables.h0000644000175000017500000001046413571215622021206 0ustar pablopablo#ifndef _X_TABLES_H #define _X_TABLES_H #include #include #define XT_FUNCTION_MAXNAMELEN 30 #define XT_EXTENSION_MAXNAMELEN 29 #define XT_TABLE_MAXNAMELEN 32 struct xt_entry_match { union { struct { __u16 match_size; /* Used by userspace */ char name[XT_EXTENSION_MAXNAMELEN]; __u8 revision; } user; struct { __u16 match_size; /* Used inside the kernel */ struct xt_match *match; } kernel; /* Total length */ __u16 match_size; } u; unsigned char data[0]; }; struct xt_entry_target { union { struct { __u16 target_size; /* Used by userspace */ char name[XT_EXTENSION_MAXNAMELEN]; __u8 revision; } user; struct { __u16 target_size; /* Used inside the kernel */ struct xt_target *target; } kernel; /* Total length */ __u16 target_size; } u; unsigned char data[0]; }; #define XT_TARGET_INIT(__name, __size) \ { \ .target.u.user = { \ .target_size = XT_ALIGN(__size), \ .name = __name, \ }, \ } struct xt_standard_target { struct xt_entry_target target; int verdict; }; struct xt_error_target { struct xt_entry_target target; char errorname[XT_FUNCTION_MAXNAMELEN]; }; /* The argument to IPT_SO_GET_REVISION_*. Returns highest revision * kernel supports, if >= revision. */ struct xt_get_revision { char name[XT_EXTENSION_MAXNAMELEN]; __u8 revision; }; /* CONTINUE verdict for targets */ #define XT_CONTINUE 0xFFFFFFFF /* For standard target */ #define XT_RETURN (-NF_REPEAT - 1) /* this is a dummy structure to find out the alignment requirement for a struct * containing all the fundamental data types that are used in ipt_entry, * ip6t_entry and arpt_entry. This sucks, and it is a hack. It will be my * personal pleasure to remove it -HW */ struct _xt_align { __u8 u8; __u16 u16; __u32 u32; __u64 u64; }; #define XT_ALIGN(s) __ALIGN_KERNEL((s), __alignof__(struct _xt_align)) /* Standard return verdict, or do jump. */ #define XT_STANDARD_TARGET "" /* Error verdict. */ #define XT_ERROR_TARGET "ERROR" #define SET_COUNTER(c,b,p) do { (c).bcnt = (b); (c).pcnt = (p); } while(0) #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0) struct xt_counters { __u64 pcnt, bcnt; /* Packet and byte counters */ }; /* The argument to IPT_SO_ADD_COUNTERS. */ struct xt_counters_info { /* Which table. */ char name[XT_TABLE_MAXNAMELEN]; unsigned int num_counters; /* The counters (actually `number' of these). */ struct xt_counters counters[0]; }; #define XT_INV_PROTO 0x40 /* Invert the sense of PROTO. */ /* fn returns 0 to continue iteration */ #define XT_MATCH_ITERATE(type, e, fn, args...) \ ({ \ unsigned int __i; \ int __ret = 0; \ struct xt_entry_match *__m; \ \ for (__i = sizeof(type); \ __i < (e)->target_offset; \ __i += __m->u.match_size) { \ __m = (void *)e + __i; \ \ __ret = fn(__m , ## args); \ if (__ret != 0) \ break; \ } \ __ret; \ }) /* fn returns 0 to continue iteration */ #define XT_ENTRY_ITERATE_CONTINUE(type, entries, size, n, fn, args...) \ ({ \ unsigned int __i, __n; \ int __ret = 0; \ type *__entry; \ \ for (__i = 0, __n = 0; __i < (size); \ __i += __entry->next_offset, __n++) { \ __entry = (void *)(entries) + __i; \ if (__n < n) \ continue; \ \ __ret = fn(__entry , ## args); \ if (__ret != 0) \ break; \ } \ __ret; \ }) /* fn returns 0 to continue iteration */ #define XT_ENTRY_ITERATE(type, entries, size, fn, args...) \ XT_ENTRY_ITERATE_CONTINUE(type, entries, size, 0, fn, args) /* pos is normally a struct ipt_entry/ip6t_entry/etc. */ #define xt_entry_foreach(pos, ehead, esize) \ for ((pos) = (typeof(pos))(ehead); \ (pos) < (typeof(pos))((char *)(ehead) + (esize)); \ (pos) = (typeof(pos))((char *)(pos) + (pos)->next_offset)) /* can only be xt_entry_match, so no use of typeof here */ #define xt_ematch_foreach(pos, entry) \ for ((pos) = (struct xt_entry_match *)entry->elems; \ (pos) < (struct xt_entry_match *)((char *)(entry) + \ (entry)->target_offset); \ (pos) = (struct xt_entry_match *)((char *)(pos) + \ (pos)->u.match_size)) #endif /* _X_TABLES_H */ arptables-0.0.5/include/libarptc/0000755000175000017500000000000013571215622015674 5ustar pablopabloarptables-0.0.5/include/libarptc/libarptc.h0000644000175000017500000001242413571215622017650 0ustar pablopablo#ifndef _LIBARPTC_H #define _LIBARPTC_H /* Library which manipulates filtering rules. */ #include #include #include #ifndef ARPT_MIN_ALIGN /* arpt_entry has pointers and uint64_t's in it, so if you align to * it, you'll also align to any crazy matches and targets someone * might write. */ #define ARPT_MIN_ALIGN (__alignof__(struct arpt_entry)) #endif #define ARPT_ALIGN(s) (((s) + ((ARPT_MIN_ALIGN)-1)) & ~((ARPT_MIN_ALIGN)-1)) typedef char arpt_chainlabel[32]; #define ARPTC_LABEL_ACCEPT "ACCEPT" #define ARPTC_LABEL_DROP "DROP" #define ARPTC_LABEL_QUEUE "QUEUE" #define ARPTC_LABEL_RETURN "RETURN" /* NF_ARP_NUMHOOKS is different on 2.4 and 2.6; hack to support both */ extern int RUNTIME_NF_ARP_NUMHOOKS; /* boy, this is dirty */ /* Transparent handle type. */ typedef struct arptc_handle *arptc_handle_t; /* Does this chain exist? */ int arptc_is_chain(const char *chain, const arptc_handle_t handle); /* Take a snapshot of the rules. Returns NULL on error. */ arptc_handle_t arptc_init(const char *tablename); /* Iterator functions to run through the chains. Returns NULL at end. */ const char *arptc_first_chain(arptc_handle_t *handle); const char *arptc_next_chain(arptc_handle_t *handle); /* Get first rule in the given chain: NULL for empty chain. */ const struct arpt_entry *arptc_first_rule(const char *chain, arptc_handle_t *handle); /* Returns NULL when rules run out. */ const struct arpt_entry *arptc_next_rule(const struct arpt_entry *prev, arptc_handle_t *handle); /* Returns a pointer to the target name of this entry. */ const char *arptc_get_target(const struct arpt_entry *e, arptc_handle_t *handle); /* Is this a built-in chain? */ int arptc_builtin(const char *chain, const arptc_handle_t handle); /* Get the policy of a given built-in chain */ const char *arptc_get_policy(const char *chain, struct arpt_counters *counter, arptc_handle_t *handle); /* These functions return TRUE for OK or 0 and set errno. If errno == 0, it means there was a version error (ie. upgrade libarptc). */ /* Rule numbers start at 1 for the first rule. */ /* Insert the entry `e' in chain `chain' into position `rulenum'. */ int arptc_insert_entry(const arpt_chainlabel chain, const struct arpt_entry *e, unsigned int rulenum, arptc_handle_t *handle); /* Atomically replace rule `rulenum' in `chain' with `e'. */ int arptc_replace_entry(const arpt_chainlabel chain, const struct arpt_entry *e, unsigned int rulenum, arptc_handle_t *handle); /* Append entry `e' to chain `chain'. Equivalent to insert with rulenum = length of chain. */ int arptc_append_entry(const arpt_chainlabel chain, const struct arpt_entry *e, arptc_handle_t *handle); /* Delete the first rule in `chain' which matches `e', subject to matchmask (array of length == origfw) */ int arptc_delete_entry(const arpt_chainlabel chain, const struct arpt_entry *origfw, unsigned char *matchmask, arptc_handle_t *handle); /* Delete the rule in position `rulenum' in `chain'. */ int arptc_delete_num_entry(const arpt_chainlabel chain, unsigned int rulenum, arptc_handle_t *handle); /* Check the packet `e' on chain `chain'. Returns the verdict, or NULL and sets errno. */ const char *arptc_check_packet(const arpt_chainlabel chain, struct arpt_entry *entry, arptc_handle_t *handle); /* Flushes the entries in the given chain (ie. empties chain). */ int arptc_flush_entries(const arpt_chainlabel chain, arptc_handle_t *handle); /* Zeroes the counters in a chain. */ int arptc_zero_entries(const arpt_chainlabel chain, arptc_handle_t *handle); /* Creates a new chain. */ int arptc_create_chain(const arpt_chainlabel chain, arptc_handle_t *handle); /* Deletes a chain. */ int arptc_delete_chain(const arpt_chainlabel chain, arptc_handle_t *handle); /* Renames a chain. */ int arptc_rename_chain(const arpt_chainlabel oldname, const arpt_chainlabel newname, arptc_handle_t *handle); /* Sets the policy on a built-in chain. */ int arptc_set_policy(const arpt_chainlabel chain, const arpt_chainlabel policy, struct arpt_counters *counters, arptc_handle_t *handle); /* Get the number of references to this chain */ int arptc_get_references(unsigned int *ref, const arpt_chainlabel chain, arptc_handle_t *handle); /* read packet and byte counters for a specific rule */ struct arpt_counters *arptc_read_counter(const arpt_chainlabel chain, unsigned int rulenum, arptc_handle_t *handle); /* zero packet and byte counters for a specific rule */ int arptc_zero_counter(const arpt_chainlabel chain, unsigned int rulenum, arptc_handle_t *handle); /* set packet and byte counters for a specific rule */ int arptc_set_counter(const arpt_chainlabel chain, unsigned int rulenum, struct arpt_counters *counters, arptc_handle_t *handle); /* Makes the actual changes. */ int arptc_commit(arptc_handle_t *handle); /* Get raw socket. */ int arptc_get_raw_socket(); /* Translates errno numbers into more human-readable form than strerror. */ const char *arptc_strerror(int err); #endif /* _LIBARPTC_H */ arptables-0.0.5/include/libarptc/arpt_kernel_headers.h0000644000175000017500000000060413571215622022046 0ustar pablopablo/* This is the userspace/kernel interface for Generic IP Chains, required for libc6. */ #ifndef _FWCHAINS_KERNEL_HEADERS_H #define _FWCHAINS_KERNEL_HEADERS_H #include #include #include #include #include #include #include #include #include #endif arptables-0.0.5/include/arptables_common.h0000644000175000017500000000132213571215622017570 0ustar pablopablo#ifndef _ARPTABLES_COMMON_H #define _ARPTABLES_COMMON_H enum exittype { OTHER_PROBLEM = 1, PARAMETER_PROBLEM, VERSION_PROBLEM }; extern void exit_printhelp() __attribute__((noreturn)); extern void exit_tryhelp(int) __attribute__((noreturn)); int check_inverse(const char option[], int *invert, int *optind, int argc); extern int string_to_number(const char *, unsigned int, unsigned int, unsigned int *); extern int iptables_insmod(const char *modname, const char *modprobe); void exit_error(enum exittype, char *, ...)__attribute__((noreturn, format(printf,2,3))); extern const char *program_name, *program_version; extern void init_extensions(void); #endif /*_IPTABLES_COMMON_H*/ arptables-0.0.5/include/arptables.h0000644000175000017500000001133213571215622016222 0ustar pablopablo#ifndef _ARPTABLES_USER_H #define _ARPTABLES_USER_H #include #include "arptables_common.h" #include "libarptc/libarptc.h" /*******************************/ /* REMOVE LATER, PUT IN KERNEL */ /*******************************/ struct arpt_entry_match { int iets; }; /*******************************/ /* END OF KERNEL REPLACEMENTS */ /*******************************/ /* Include file for additions: new matches and targets. */ struct arptables_match { struct arptables_match *next; arpt_chainlabel name; const char *version; /* Size of match data. */ size_t size; /* Size of match data relevent for userspace comparison purposes */ size_t userspacesize; /* Revision of target (0 by default). */ uint8_t revision; /* Function which prints out usage message. */ void (*help)(void); /* Initialize the match. */ void (*init)(struct arpt_entry_match *m, unsigned int *nfcache); /* Function which parses command options; returns true if it ate an option */ int (*parse)(int c, char **argv, int invert, unsigned int *flags, const struct arpt_entry *entry, unsigned int *nfcache, struct arpt_entry_match **match); /* Final check; exit if not ok. */ void (*final_check)(unsigned int flags); /* Prints out the match iff non-NULL: put space at end */ void (*print)(const struct arpt_arp *ip, const struct arpt_entry_match *match, int numeric); /* Saves the match info in parsable form to stdout. */ void (*save)(const struct arpt_arp *ip, const struct arpt_entry_match *match); /* Pointer to list of extra command-line options */ const struct option *extra_opts; /* Ignore these men behind the curtain: */ unsigned int option_offset; struct arpt_entry_match *m; unsigned int mflags; unsigned int used; unsigned int loaded; /* simulate loading so options are merged properly */ }; struct arptables_target { struct arptables_target *next; arpt_chainlabel name; const char *version; /* Size of target data. */ size_t size; /* Size of target data relevent for userspace comparison purposes */ size_t userspacesize; /* Revision of target (0 by default). */ uint8_t revision; /* Function which prints out usage message. */ void (*help)(void); /* Initialize the target. */ void (*init)(struct arpt_entry_target *t); /* Function which parses command options; returns true if it ate an option */ int (*parse)(int c, char **argv, int invert, unsigned int *flags, const struct arpt_entry *entry, struct arpt_entry_target **target); /* Final check; exit if not ok. */ void (*final_check)(unsigned int flags); /* Prints out the target iff non-NULL: put space at end */ void (*print)(const struct arpt_arp *ip, const struct arpt_entry_target *target, int numeric); /* Saves the targinfo in parsable form to stdout. */ void (*save)(const struct arpt_arp *ip, const struct arpt_entry_target *target); /* Pointer to list of extra command-line options */ struct option *extra_opts; /* Ignore these men behind the curtain: */ unsigned int option_offset; struct arpt_entry_target *t; unsigned int tflags; unsigned int used; unsigned int loaded; /* simulate loading so options are merged properly */ }; /* Your shared library should call one of these. */ extern void register_match(struct arptables_match *me); extern void register_target(struct arptables_target *me); extern struct in_addr *dotted_to_addr(const char *dotted); extern char *addr_to_dotted(const struct in_addr *addrp); extern char *addr_to_anyname(const struct in_addr *addr); extern char *mask_to_dotted(const struct in_addr *mask); extern void parse_hostnetworkmask(const char *name, struct in_addr **addrpp, struct in_addr *maskp, unsigned int *naddrs); extern uint16_t parse_protocol(const char *s); extern int do_command(int argc, char *argv[], char **table, arptc_handle_t *handle); /* Keeping track of external matches and targets: linked lists. */ extern struct arptables_match *arptables_matches; extern struct arptables_target *arptables_targets; enum arpt_tryload { DONT_LOAD, TRY_LOAD, LOAD_MUST_SUCCEED }; extern struct arptables_target *find_target(const char *name, enum arpt_tryload); extern struct arptables_match *find_match(const char *name, enum arpt_tryload); extern int delete_chain(const arpt_chainlabel chain, int verbose, arptc_handle_t *handle); extern int flush_entries(const arpt_chainlabel chain, int verbose, arptc_handle_t *handle); extern int for_each_chain(int (*fn)(const arpt_chainlabel, int, arptc_handle_t *), int verbose, int builtinstoo, arptc_handle_t *handle); struct in_addr *parse_hostnetwork(const char *name, unsigned int *naddrs); void print_mac(const unsigned char *mac, int l); #endif /*_ARPTABLES_USER_H*/ arptables-0.0.5/extensions/0000755000175000017500000000000013571215622014650 5ustar pablopabloarptables-0.0.5/extensions/arpt_standard.c0000644000175000017500000000250313571215622017642 0ustar pablopablo/* Shared library add-on to arptables for standard target support. */ #include #include #include #include #include #include #include /* Function which prints out usage message. */ static void help(void) { printf( "Standard v%s options:\n" "(If target is DROP, ACCEPT, RETURN or nothing)\n", ARPTABLES_VERSION); } static struct option opts[] = { {0} }; /* Initialize the target. */ static void init(struct arpt_entry_target *t) { } /* Function which parses command options; returns true if it ate an option */ static int parse(int c, char **argv, int invert, unsigned int *flags, const struct arpt_entry *entry, struct arpt_entry_target **target) { return 0; } /* Final check; don't care. */ static void final_check(unsigned int flags) { } /* Saves the targinfo in parsable form to stdout. */ static void save(const struct arpt_arp *ip, const struct arpt_entry_target *target) { } static struct arptables_target standard = { NULL, "standard", ARPTABLES_VERSION, ARPT_ALIGN(sizeof(int)), ARPT_ALIGN(sizeof(int)), 0, &help, &init, &parse, &final_check, NULL, /* print */ &save, opts }; static void _init(void) __attribute__ ((constructor)); static void _init(void) { register_target(&standard); } arptables-0.0.5/extensions/arpt_mangle.c0000644000175000017500000001246413571215622017314 0ustar pablopablo#include #include #include #include #include #include #include #include static void help(void) { printf( "mangle target v%s options:\n" "--mangle-ip-s IP address\n" "--mangle-ip-d IP address\n" "--mangle-mac-s MAC address\n" "--mangle-mac-d MAC address\n" "--mangle-target target (DROP, CONTINUE or ACCEPT -- default is ACCEPT)\n", ARPTABLES_VERSION); } #define MANGLE_IPS '1' #define MANGLE_IPT '2' #define MANGLE_DEVS '3' #define MANGLE_DEVT '4' #define MANGLE_TARGET '5' static struct option opts[] = { { "mangle-ip-s" , required_argument, 0, MANGLE_IPS }, { "mangle-ip-d" , required_argument, 0, MANGLE_IPT }, { "mangle-mac-s" , required_argument, 0, MANGLE_DEVS }, { "mangle-mac-d" , required_argument, 0, MANGLE_DEVT }, { "mangle-target" , required_argument, 0, MANGLE_TARGET }, {0} }; static void init(struct arpt_entry_target *t) { struct arpt_mangle *mangle = (struct arpt_mangle *) t->data; mangle->target = NF_ACCEPT; } static int parse(int c, char **argv, int invert, unsigned int *flags, const struct arpt_entry *e, struct arpt_entry_target **t) { struct arpt_mangle *mangle = (struct arpt_mangle *)(*t)->data; struct in_addr *ipaddr; struct ether_addr *macaddr; int ret = 1; switch (c) { case MANGLE_IPS: /* if (e->arp.arpln_mask == 0) exit_error(PARAMETER_PROBLEM, "no pln defined"); if (e->arp.invflags & ARPT_INV_ARPPLN) exit_error(PARAMETER_PROBLEM, "! pln not allowed for --mangle-ip-s"); */ /* if (e->arp.arpln != 4) exit_error(PARAMETER_PROBLEM, "only pln=4 supported"); */ { unsigned int nr; ipaddr = parse_hostnetwork(argv[optind-1], &nr); } mangle->u_s.src_ip.s_addr = ipaddr->s_addr; free(ipaddr); mangle->flags |= ARPT_MANGLE_SIP; break; case MANGLE_IPT: /* if (e->arp.arpln_mask == 0) exit_error(PARAMETER_PROBLEM, "no pln defined"); if (e->arp.invflags & ARPT_INV_ARPPLN) exit_error(PARAMETER_PROBLEM, "! pln not allowed for --mangle-ip-d"); */ /* if (e->arp.arpln != 4) exit_error(PARAMETER_PROBLEM, "only pln=4 supported"); */ { unsigned int nr; ipaddr = parse_hostnetwork(argv[optind-1], &nr); } mangle->u_t.tgt_ip.s_addr = ipaddr->s_addr; free(ipaddr); mangle->flags |= ARPT_MANGLE_TIP; break; case MANGLE_DEVS: if (e->arp.arhln_mask == 0) exit_error(PARAMETER_PROBLEM, "no --h-length defined"); if (e->arp.invflags & ARPT_INV_ARPHLN) exit_error(PARAMETER_PROBLEM, "! --h-length not allowed for " "--mangle-mac-s"); if (e->arp.arhln != 6) exit_error(PARAMETER_PROBLEM, "only --h-length 6 " "supported"); macaddr = ether_aton(argv[optind-1]); if (macaddr == NULL) exit_error(PARAMETER_PROBLEM, "invalid source MAC"); memcpy(mangle->src_devaddr, macaddr, e->arp.arhln); mangle->flags |= ARPT_MANGLE_SDEV; break; case MANGLE_DEVT: if (e->arp.arhln_mask == 0) exit_error(PARAMETER_PROBLEM, "no --h-length defined"); if (e->arp.invflags & ARPT_INV_ARPHLN) exit_error(PARAMETER_PROBLEM, "! hln not allowed for --mangle-mac-d"); if (e->arp.arhln != 6) exit_error(PARAMETER_PROBLEM, "only --h-length 6 " "supported"); macaddr = ether_aton(argv[optind-1]); if (macaddr == NULL) exit_error(PARAMETER_PROBLEM, "invalid target MAC"); memcpy(mangle->tgt_devaddr, macaddr, e->arp.arhln); mangle->flags |= ARPT_MANGLE_TDEV; break; case MANGLE_TARGET: if (!strcmp(argv[optind-1], "DROP")) mangle->target = NF_DROP; else if (!strcmp(argv[optind-1], "ACCEPT")) mangle->target = NF_ACCEPT; else if (!strcmp(argv[optind-1], "CONTINUE")) mangle->target = ARPT_CONTINUE; else exit_error(PARAMETER_PROBLEM, "bad target for " "--mangle-target"); break; default: ret = 0; } return ret; } static void final_check(unsigned int flags) { } static void print(const struct arpt_arp *ip, const struct arpt_entry_target *target, int numeric) { struct arpt_mangle *m = (struct arpt_mangle *)(target->data); char buf[100]; if (m->flags & ARPT_MANGLE_SIP) { if (numeric) sprintf(buf, "%s", addr_to_dotted(&(m->u_s.src_ip))); else sprintf(buf, "%s", addr_to_anyname(&(m->u_s.src_ip))); printf("--mangle-ip-s %s ", buf); } if (m->flags & ARPT_MANGLE_SDEV) { printf("--mangle-mac-s "); print_mac((unsigned char *)m->src_devaddr, 6); printf(" "); } if (m->flags & ARPT_MANGLE_TIP) { if (numeric) sprintf(buf, "%s", addr_to_dotted(&(m->u_t.tgt_ip))); else sprintf(buf, "%s", addr_to_anyname(&(m->u_t.tgt_ip))); printf("--mangle-ip-d %s ", buf); } if (m->flags & ARPT_MANGLE_TDEV) { printf("--mangle-mac-d "); print_mac((unsigned char *)m->tgt_devaddr, 6); printf(" "); } if (m->target != NF_ACCEPT) { printf("--mangle-target "); if (m->target == NF_DROP) printf("DROP "); else printf("CONTINUE "); } } static void save(const struct arpt_arp *ip, const struct arpt_entry_target *target) { } static struct arptables_target change = { NULL, "mangle", ARPTABLES_VERSION, ARPT_ALIGN(sizeof(struct arpt_mangle)), ARPT_ALIGN(sizeof(struct arpt_mangle)), 0, &help, &init, &parse, &final_check, &print, &save, opts }; static void _init(void) __attribute__ ((constructor)); static void _init(void) { register_target(&change); } arptables-0.0.5/extensions/arpt_MARK.c0000644000175000017500000000777413571215622016613 0ustar pablopablo/* * (C) 2014 by Gao Feng * * arpt_MARK.c -- arptables extension to set mark for arp packet * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include static void help(void) { printf( "MARK target v%s options:\n" "--set-mark mark : set the mark value\n" "--and-mark value : binary AND the mark with value\n" "--or-mark value : binary OR the mark with value\n", ARPTABLES_VERSION); } #define MARK_OPT 1 #define AND_MARK_OPT 2 #define OR_MARK_OPT 3 static struct option opts[] = { { .name = "set-mark", .has_arg = required_argument, .flag = 0, .val = MARK_OPT }, { .name = "and-mark", .has_arg = required_argument, .flag = 0, .val = AND_MARK_OPT }, { .name = "or-mark", .has_arg = required_argument, .flag = 0, .val = OR_MARK_OPT }, { .name = NULL} }; static void init(struct arpt_entry_target *t) { struct xt_mark_tginfo2 *info = (struct xt_mark_tginfo2 *) t->data; info->mark = 0; } static int parse(int c, char **argv, int invert, unsigned int *flags, const struct arpt_entry *e, struct arpt_entry_target **t) { struct xt_mark_tginfo2 *info = (struct xt_mark_tginfo2 *)(*t)->data; int i; switch (c) { case MARK_OPT: if (sscanf(argv[optind-1], "%x", &i) != 1) { exit_error(PARAMETER_PROBLEM, "Bad mark value `%s'", optarg); return 0; } info->mark = i; if (*flags) exit_error(PARAMETER_PROBLEM, "MARK: Can't specify --set-mark twice"); *flags = 1; break; case AND_MARK_OPT: if (sscanf(argv[optind-1], "%x", &i) != 1) { exit_error(PARAMETER_PROBLEM, "Bad mark value `%s'", optarg); return 0; } info->mark = 0; info->mask = ~i; if (*flags) exit_error(PARAMETER_PROBLEM, "MARK: Can't specify --and-mark twice"); *flags = 1; break; case OR_MARK_OPT: if (sscanf(argv[optind-1], "%x", &i) != 1) { exit_error(PARAMETER_PROBLEM, "Bad mark value `%s'", optarg); return 0; } info->mark = info->mask = i; if (*flags) exit_error(PARAMETER_PROBLEM, "MARK: Can't specify --or-mark twice"); *flags = 1; break; default: return 0; } return 1; } static void final_check(unsigned int flags) { if (!flags) exit_error(PARAMETER_PROBLEM, "MARK: Parameter --set-mark/--and-mark/--or-mark is required"); } static void print(const struct arpt_arp *ip, const struct arpt_entry_target *target, int numeric) { struct xt_mark_tginfo2 *info = (struct xt_mark_tginfo2 *)(target->data); if (info->mark == 0) printf("--and-mark %x", (unsigned int)(uint32_t)~info->mask); else if (info->mark == info->mask) printf("--or-mark %x", info->mark); else printf("--set-mark %x", info->mark); } static void save(const struct arpt_arp *ip, const struct arpt_entry_target *target) { } static struct arptables_target mark = { .next = NULL, .name = "MARK", .version = ARPTABLES_VERSION, .size = ARPT_ALIGN(sizeof(struct xt_mark_tginfo2)), .userspacesize = ARPT_ALIGN(sizeof(struct xt_mark_tginfo2)), .revision = 2, .help = help, .init = init, .parse = parse, .final_check = final_check, .print = print, .save = save, .extra_opts = opts }; static void _init(void) __attribute__ ((constructor)); static void _init(void) { register_target(&mark); } arptables-0.0.5/extensions/arpt_CLASSIFY.c0000644000175000017500000000603613571215622017264 0ustar pablopablo/* * (C) 2010 by Frederic Leroy * * arpt_classify.c -- arptables extension to classify arp packet * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #define TC_H_MAJ_MASK (0xFFFF0000U) #define TC_H_MIN_MASK (0x0000FFFFU) #define TC_H_MAJ(h) ((h)&TC_H_MAJ_MASK) #define TC_H_MIN(h) ((h)&TC_H_MIN_MASK) #define TC_H_MAKE(maj,min) (((maj)&TC_H_MAJ_MASK)|((min)&TC_H_MIN_MASK)) static void help(void) { printf( "CLASSIFY target v%s options:\n" "--set-class major:minor : set the major and minor class value\n", ARPTABLES_VERSION); } #define CLASSIFY_OPT 1 static struct option opts[] = { { "set-class" , required_argument, 0, CLASSIFY_OPT }, {0} }; static void init(struct arpt_entry_target *t) { struct xt_classify_target_info *classify = (struct xt_classify_target_info *) t->data; classify->priority = 0; } static int parse(int c, char **argv, int invert, unsigned int *flags, const struct arpt_entry *e, struct arpt_entry_target **t) { struct xt_classify_target_info *classify = (struct xt_classify_target_info *)(*t)->data; int i,j; switch (c) { case CLASSIFY_OPT: if (sscanf(argv[optind-1], "%x:%x", &i, &j) != 2) { exit_error(PARAMETER_PROBLEM, "Bad class value `%s'", optarg); return 0; } classify->priority = TC_H_MAKE(i<<16, j); if (*flags) exit_error(PARAMETER_PROBLEM, "CLASSIFY: Can't specify --set-class twice"); *flags = 1; break; default: return 0; } return 1; } static void final_check(unsigned int flags) { if (!flags) exit_error(PARAMETER_PROBLEM, "CLASSIFY: Parameter --set-class is required"); } static void print(const struct arpt_arp *ip, const struct arpt_entry_target *target, int numeric) { struct xt_classify_target_info *t = (struct xt_classify_target_info *)(target->data); printf("--set-class %x:%x ", TC_H_MAJ(t->priority)>>16, TC_H_MIN(t->priority)); } static void save(const struct arpt_arp *ip, const struct arpt_entry_target *target) { } static struct arptables_target classify = { NULL, "CLASSIFY", ARPTABLES_VERSION, ARPT_ALIGN(sizeof(struct xt_classify_target_info)), ARPT_ALIGN(sizeof(struct xt_classify_target_info)), 0, &help, &init, &parse, &final_check, &print, &save, opts }; static void _init(void) __attribute__ ((constructor)); static void _init(void) { register_target(&classify); } arptables-0.0.5/extensions/Makefile0000644000175000017500000000036713571215622016316 0ustar pablopablo#! /usr/bin/make EXT_FUNC+=standard mangle CLASSIFY MARK EXT_OBJS+=$(foreach T,$(EXT_FUNC), extensions/arpt_$(T).o) extensions/ebt_%.o: extensions/arpt_%.c include/arptables.h include/arptables_common.h $(CC) $(CFLAGS) $(PROGSPECS) -c -o $@ $< arptables-0.0.5/arptables.c0000644000175000017500000017032513571215622014602 0ustar pablopablo/* Code to take an arptables-style command line and do it. */ /* * arptables: * Author: Bart De Schuymer , but * almost all code is from the iptables userspace program, which has main * authors: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Currently, only support for specifying hardware addresses for Ethernet is available. This tool is not luser-proof: you can specify an Ethernet source address and set hardware length to something different than 6, f.e. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #ifndef ARPT_LIB_DIR #define ARPT_LIB_DIR "/usr/local/lib/arptables" #endif #ifndef PROC_SYS_MODPROBE #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" #endif #define FMT_NUMERIC 0x0001 #define FMT_NOCOUNTS 0x0002 #define FMT_KILOMEGAGIGA 0x0004 #define FMT_OPTIONS 0x0008 #define FMT_NOTABLE 0x0010 #define FMT_NOTARGET 0x0020 #define FMT_VIA 0x0040 #define FMT_NONEWLINE 0x0080 #define FMT_LINENUMBERS 0x0100 #define FMT_PRINT_RULE (FMT_NOCOUNTS | FMT_OPTIONS | FMT_VIA \ | FMT_NUMERIC | FMT_NOTABLE) #define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (notab)) #define CMD_NONE 0x0000U #define CMD_INSERT 0x0001U #define CMD_DELETE 0x0002U #define CMD_DELETE_NUM 0x0004U #define CMD_REPLACE 0x0008U #define CMD_APPEND 0x0010U #define CMD_LIST 0x0020U #define CMD_FLUSH 0x0040U #define CMD_ZERO 0x0080U #define CMD_NEW_CHAIN 0x0100U #define CMD_DELETE_CHAIN 0x0200U #define CMD_SET_POLICY 0x0400U #define CMD_CHECK 0x0800U #define CMD_RENAME_CHAIN 0x1000U #define NUMBER_OF_CMD 13 static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z', 'N', 'X', 'P', 'E' }; #define OPTION_OFFSET 256 #define OPT_NONE 0x00000U #define OPT_NUMERIC 0x00001U #define OPT_S_IP 0x00002U #define OPT_D_IP 0x00004U #define OPT_S_MAC 0x00008U #define OPT_D_MAC 0x00010U #define OPT_H_LENGTH 0x00020U #define OPT_P_LENGTH 0x00040U #define OPT_OPCODE 0x00080U #define OPT_H_TYPE 0x00100U #define OPT_P_TYPE 0x00200U #define OPT_JUMP 0x00400U #define OPT_VERBOSE 0x00800U #define OPT_VIANAMEIN 0x01000U #define OPT_VIANAMEOUT 0x02000U #define OPT_LINENUMBERS 0x04000U #define OPT_COUNTERS 0x08000U #define NUMBER_OF_OPT 16 static const char optflags[NUMBER_OF_OPT] = { 'n', 's', 'd', 2, 3, 7, 8, 4, 5, 6, 'j', 'v', 'i', 'o', '0', 'c'}; static struct option original_opts[] = { { "append", 1, 0, 'A' }, { "delete", 1, 0, 'D' }, { "insert", 1, 0, 'I' }, { "replace", 1, 0, 'R' }, { "list", 2, 0, 'L' }, { "flush", 2, 0, 'F' }, { "zero", 2, 0, 'Z' }, { "new-chain", 1, 0, 'N' }, { "delete-chain", 2, 0, 'X' }, { "rename-chain", 1, 0, 'E' }, { "policy", 1, 0, 'P' }, { "source-ip", 1, 0, 's' }, { "destination-ip", 1, 0, 'd' }, { "src-ip", 1, 0, 's' }, { "dst-ip", 1, 0, 'd' }, { "source-mac", 1, 0, 2}, { "destination-mac", 1, 0, 3}, { "src-mac", 1, 0, 2}, { "dst-mac", 1, 0, 3}, { "h-length", 1, 0, 'l' }, { "p-length", 1, 0, 8 }, { "opcode", 1, 0, 4 }, { "h-type", 1, 0, 5 }, { "proto-type", 1, 0, 6 }, { "in-interface", 1, 0, 'i' }, { "jump", 1, 0, 'j' }, { "table", 1, 0, 't' }, { "match", 1, 0, 'm' }, { "numeric", 0, 0, 'n' }, { "out-interface", 1, 0, 'o' }, { "verbose", 0, 0, 'v' }, { "exact", 0, 0, 'x' }, { "version", 0, 0, 'V' }, { "help", 2, 0, 'h' }, { "line-numbers", 0, 0, '0' }, { "modprobe", 1, 0, 'M' }, { "set-counters", 1, 0, 'c' }, { 0 } }; int RUNTIME_NF_ARP_NUMHOOKS = 3; /*#ifndef __OPTIMIZE__ struct arpt_entry_target * arpt_get_target(struct arpt_entry *e) { return (void *)e + e->target_offset; } #endif*/ static struct option *opts = original_opts; static unsigned int global_option_offset = 0; /* Table of legal combinations of commands and options. If any of the * given commands make an option legal, that option is legal (applies to * CMD_LIST and CMD_ZERO only). * Key: * + compulsory * x illegal * optional */ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { /* -n -s -d -p -j -v -x -i -o -f --line */ /*INSERT*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}, /*DELETE*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}, /*DELETE_NUM*/{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}, /*REPLACE*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}, /*APPEND*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}, /*LIST*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}, /*FLUSH*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}, /*ZERO*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}, /*NEW_CHAIN*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}, /*DEL_CHAIN*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}, /*SET_POLICY*/{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}, /*CHECK*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}, /*RENAME*/ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '} }; static int inverse_for_options[NUMBER_OF_OPT] = { /* -n */ 0, /* -s */ ARPT_INV_SRCIP, /* -d */ ARPT_INV_TGTIP, /* 2 */ ARPT_INV_SRCDEVADDR, /* 3 */ ARPT_INV_TGTDEVADDR, /* -l */ ARPT_INV_ARPHLN, /* 8 */ 0, /* 4 */ ARPT_INV_ARPOP, /* 5 */ ARPT_INV_ARPHRD, /* 6 */ ARPT_INV_ARPPRO, /* -j */ 0, /* -v */ 0, /* -i */ ARPT_INV_VIA_IN, /* -o */ ARPT_INV_VIA_OUT, /*--line*/ 0, /* -c */ 0, }; const char *program_version = ARPTABLES_VERSION; const char *program_name; /* Keeping track of external matches and targets: linked lists. */ struct arptables_match *arptables_matches = NULL; struct arptables_target *arptables_targets = NULL; /* Extra debugging from libarptc */ extern void dump_entries(const arptc_handle_t handle); /* A few hardcoded protocols for 'all' and in case the user has no /etc/protocols */ struct pprot { char *name; uint8_t num; }; /* Primitive headers... */ /* defined in netinet/in.h */ #if 0 #ifndef IPPROTO_ESP #define IPPROTO_ESP 50 #endif #ifndef IPPROTO_AH #define IPPROTO_AH 51 #endif #endif /***********************************************/ /* ARPTABLES SPECIFIC NEW FUNCTIONS ADDED HERE */ /***********************************************/ unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0}; unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0}; unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0}; unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0}; unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255}; unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255}; /* a few names */ static char *opcodes[] = { "Request", "Reply", "Request_Reverse", "Reply_Reverse", "DRARP_Request", "DRARP_Reply", "DRARP_Error", "InARP_Request", "ARP_NAK", }; #define NUMOPCODES 9 /* * put the mac address into 6 (ETH_ALEN) bytes */ int getmac_and_mask(char *from, char *to, char *mask) { char *p; int i; struct ether_addr *addr; if (strcasecmp(from, "Unicast") == 0) { memcpy(to, mac_type_unicast, ETH_ALEN); memcpy(mask, msk_type_unicast, ETH_ALEN); return 0; } if (strcasecmp(from, "Multicast") == 0) { memcpy(to, mac_type_multicast, ETH_ALEN); memcpy(mask, msk_type_multicast, ETH_ALEN); return 0; } if (strcasecmp(from, "Broadcast") == 0) { memcpy(to, mac_type_broadcast, ETH_ALEN); memcpy(mask, msk_type_broadcast, ETH_ALEN); return 0; } if ( (p = strrchr(from, '/')) != NULL) { *p = '\0'; if (!(addr = ether_aton(p + 1))) return -1; memcpy(mask, addr, ETH_ALEN); } else memset(mask, 0xff, ETH_ALEN); if (!(addr = ether_aton(from))) return -1; memcpy(to, addr, ETH_ALEN); for (i = 0; i < ETH_ALEN; i++) to[i] &= mask[i]; return 0; } int getlength_and_mask(char *from, uint8_t *to, uint8_t *mask) { char *p, *buffer; int i; if ( (p = strrchr(from, '/')) != NULL) { *p = '\0'; i = strtol(p+1, &buffer, 10); if (*buffer != '\0' || i < 0 || i > 255) return -1; *mask = (uint8_t)i; } else *mask = 255; i = strtol(from, &buffer, 10); if (*buffer != '\0' || i < 0 || i > 255) return -1; *to = (uint8_t)i; return 0; } int get16_and_mask(char *from, uint16_t *to, uint16_t *mask, int base) { char *p, *buffer; int i; if ( (p = strrchr(from, '/')) != NULL) { *p = '\0'; i = strtol(p+1, &buffer, base); if (*buffer != '\0' || i < 0 || i > 65535) return -1; *mask = htons((uint16_t)i); } else *mask = 65535; i = strtol(from, &buffer, base); if (*buffer != '\0' || i < 0 || i > 65535) return -1; *to = htons((uint16_t)i); return 0; } void print_mac(const unsigned char *mac, int l) { int j; for (j = 0; j < l; j++) printf("%02x%s", mac[j], (j==l-1) ? "" : ":"); } void print_mac_and_mask(const unsigned char *mac, const unsigned char *mask, int l) { int i; print_mac(mac, l); for (i = 0; i < l ; i++) if (mask[i] != 255) break; if (i == l) return; printf("/"); print_mac(mask, l); } /*********************************************/ /* ARPTABLES SPECIFIC NEW FUNCTIONS END HERE */ /*********************************************/ struct in_addr * dotted_to_addr(const char *dotted) { static struct in_addr addr; unsigned char *addrp; char *p, *q; unsigned int onebyte; int i; char buf[20]; /* copy dotted string, because we need to modify it */ strncpy(buf, dotted, sizeof(buf) - 1); addrp = (unsigned char *) &(addr.s_addr); p = buf; for (i = 0; i < 3; i++) { if ((q = strchr(p, '.')) == NULL) return (struct in_addr *) NULL; *q = '\0'; if (string_to_number(p, 0, 255, &onebyte) == -1) return (struct in_addr *) NULL; addrp[i] = (unsigned char) onebyte; p = q + 1; } /* we've checked 3 bytes, now we check the last one */ if (string_to_number(p, 0, 255, &onebyte) == -1) return (struct in_addr *) NULL; addrp[3] = (unsigned char) onebyte; return &addr; } static struct in_addr * network_to_addr(const char *name) { struct netent *net; static struct in_addr addr; if ((net = getnetbyname(name)) != NULL) { if (net->n_addrtype != AF_INET) return (struct in_addr *) NULL; addr.s_addr = htonl((unsigned long) net->n_net); return &addr; } return (struct in_addr *) NULL; } static void inaddrcpy(struct in_addr *dst, struct in_addr *src) { /* memcpy(dst, src, sizeof(struct in_addr)); */ dst->s_addr = src->s_addr; } void exit_error(enum exittype status, char *msg, ...) { va_list args; va_start(args, msg); fprintf(stderr, "%s v%s: ", program_name, program_version); vfprintf(stderr, msg, args); va_end(args); fprintf(stderr, "\n"); if (status == PARAMETER_PROBLEM) exit_tryhelp(status); if (status == VERSION_PROBLEM) fprintf(stderr, "Perhaps arptables or your kernel needs to be upgraded.\n"); exit(status); } void exit_tryhelp(int status) { fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", program_name, program_name ); exit(status); } void exit_printhelp(void) { struct arptables_match *m = NULL; struct arptables_target *t = NULL; int i; printf("%s v%s (legacy)\n\n" "Usage: %s -[AD] chain rule-specification [options]\n" " %s -[RI] chain rulenum rule-specification [options]\n" " %s -D chain rulenum [options]\n" " %s -[LFZ] [chain] [options]\n" " %s -[NX] chain\n" " %s -E old-chain-name new-chain-name\n" " %s -P chain target [options]\n" " %s -h (print this help information)\n\n", program_name, program_version, program_name, program_name, program_name, program_name, program_name, program_name, program_name, program_name); printf( "Commands:\n" "Either long or short options are allowed.\n" " --append -A chain Append to chain\n" " --delete -D chain Delete matching rule from chain\n" " --delete -D chain rulenum\n" " Delete rule rulenum (1 = first) from chain\n" " --insert -I chain [rulenum]\n" " Insert in chain as rulenum (default 1=first)\n" " --replace -R chain rulenum\n" " Replace rule rulenum (1 = first) in chain\n" " --list -L [chain] List the rules in a chain or all chains\n" " --flush -F [chain] Delete all rules in chain or all chains\n" " --zero -Z [chain] Zero counters in chain or all chains\n" " --new -N chain Create a new user-defined chain\n" " --delete-chain\n" " -X [chain] Delete a user-defined chain\n" " --policy -P chain target\n" " Change policy on chain to target\n" " --rename-chain\n" " -E old-chain new-chain\n" " Change chain name, (moving any references)\n" "Options:\n" " --source-ip -s [!] address[/mask]\n" " source specification\n" " --destination-ip -d [!] address[/mask]\n" " destination specification\n" " --source-mac [!] address[/mask]\n" " --destination-mac [!] address[/mask]\n" " --h-length -l length[/mask] hardware length (nr of bytes)\n" " --opcode code[/mask] operation code (2 bytes)\n" " --h-type type[/mask] hardware type (2 bytes, hexadecimal)\n" " --proto-type type[/mask] protocol type (2 bytes)\n" " --in-interface -i [!] input name[+]\n" " network interface name ([+] for wildcard)\n" " --out-interface -o [!] output name[+]\n" " network interface name ([+] for wildcard)\n" " --jump -j target\n" " target for rule (may load target extension)\n" " --match -m match\n" " extended match (may load extension)\n" " --numeric -n numeric output of addresses and ports\n" " --table -t table table to manipulate (default: `filter')\n" " --verbose -v verbose mode\n" " --line-numbers print line numbers when listing\n" " --exact -x expand numbers (display exact values)\n" " --modprobe= try to insert modules using this command\n" " --set-counters -c PKTS BYTES set the counter during insert/append\n" "[!] --version -V print package version.\n"); printf(" opcode strings: \n"); for (i = 0; i < NUMOPCODES; i++) printf(" %d = %s\n", i + 1, opcodes[i]); printf( " hardware type string: 1 = Ethernet\n" " protocol type string: 0x800 = IPv4\n"); /* Print out any special helps. A user might like to be able to add a --help to the commandline, and see expected results. So we call help for all matches & targets */ for (t=arptables_targets;t;t=t->next) { printf("\n"); t->help(); } for (m=arptables_matches;m;m=m->next) { printf("\n"); m->help(); } exit(0); } static void generic_opt_check(int command, int options) { int i, j, legal = 0; /* Check that commands are valid with options. Complicated by the * fact that if an option is legal with *any* command given, it is * legal overall (ie. -z and -l). */ for (i = 0; i < NUMBER_OF_OPT; i++) { legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */ for (j = 0; j < NUMBER_OF_CMD; j++) { if (!(command & (1< 1; option >>= 1, ptr++); return *ptr; } static char cmd2char(int option) { const char *ptr; for (ptr = cmdflags; option > 1; option >>= 1, ptr++); return *ptr; } static void add_command(unsigned int *cmd, const int newcmd, const unsigned int othercmds, int invert) { if (invert) exit_error(PARAMETER_PROBLEM, "unexpected ! flag"); if (*cmd & (~othercmds)) exit_error(PARAMETER_PROBLEM, "Can't use -%c with -%c\n", cmd2char(newcmd), cmd2char(*cmd & (~othercmds))); *cmd |= newcmd; } int check_inverse(const char option[], int *invert, int *optind, int argc) { if (option && strcmp(option, "!") == 0) { if (*invert) exit_error(PARAMETER_PROBLEM, "Multiple `!' flags not allowed"); *invert = TRUE; if (optind) { *optind = *optind+1; if (argc && *optind > argc) exit_error(PARAMETER_PROBLEM, "no argument following `!'"); } return TRUE; } return FALSE; } static void * fw_calloc(size_t count, size_t size) { void *p; if ((p = calloc(count, size)) == NULL) { perror("arptables: calloc failed"); exit(1); } return p; } static void * fw_malloc(size_t size) { void *p; if ((p = malloc(size)) == NULL) { perror("arptables: malloc failed"); exit(1); } return p; } static struct in_addr * host_to_addr(const char *name, unsigned int *naddr) { struct hostent *host; struct in_addr *addr; unsigned int i; *naddr = 0; if ((host = gethostbyname(name)) != NULL) { if (host->h_addrtype != AF_INET || host->h_length != sizeof(struct in_addr)) return (struct in_addr *) NULL; while (host->h_addr_list[*naddr] != (char *) NULL) (*naddr)++; addr = fw_calloc(*naddr, sizeof(struct in_addr)); for (i = 0; i < *naddr; i++) inaddrcpy(&(addr[i]), (struct in_addr *) host->h_addr_list[i]); return addr; } return (struct in_addr *) NULL; } static char * addr_to_host(const struct in_addr *addr) { struct hostent *host; if ((host = gethostbyaddr((char *) addr, sizeof(struct in_addr), AF_INET)) != NULL) return (char *) host->h_name; return (char *) NULL; } /* * All functions starting with "parse" should succeed, otherwise * the program fails. * Most routines return pointers to static data that may change * between calls to the same or other routines with a few exceptions: * "host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask" * return global static data. */ struct in_addr * parse_hostnetwork(const char *name, unsigned int *naddrs) { struct in_addr *addrp, *addrptmp; if ((addrptmp = dotted_to_addr(name)) != NULL || (addrptmp = network_to_addr(name)) != NULL) { addrp = fw_malloc(sizeof(struct in_addr)); inaddrcpy(addrp, addrptmp); *naddrs = 1; return addrp; } if ((addrp = host_to_addr(name, naddrs)) != NULL) return addrp; exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name); } static struct in_addr * parse_mask(char *mask) { static struct in_addr maskaddr; struct in_addr *addrp; unsigned int bits; if (mask == NULL) { /* no mask at all defaults to 32 bits */ maskaddr.s_addr = 0xFFFFFFFF; return &maskaddr; } if ((addrp = dotted_to_addr(mask)) != NULL) /* dotted_to_addr already returns a network byte order addr */ return addrp; if (string_to_number(mask, 0, 32, &bits) == -1) exit_error(PARAMETER_PROBLEM, "invalid mask `%s' specified", mask); if (bits != 0) { maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits)); return &maskaddr; } maskaddr.s_addr = 0L; return &maskaddr; } void parse_hostnetworkmask(const char *name, struct in_addr **addrpp, struct in_addr *maskp, unsigned int *naddrs) { struct in_addr *addrp; char buf[256]; char *p; int i, j, k, n; strncpy(buf, name, sizeof(buf) - 1); buf[sizeof(buf) - 1] = '\0'; if ((p = strrchr(buf, '/')) != NULL) { *p = '\0'; addrp = parse_mask(p + 1); } else addrp = parse_mask(NULL); inaddrcpy(maskp, addrp); /* if a null mask is given, the name is ignored, like in "any/0" */ if (maskp->s_addr == 0L) strcpy(buf, "0.0.0.0"); addrp = *addrpp = parse_hostnetwork(buf, naddrs); n = *naddrs; for (i = 0, j = 0; i < n; i++) { addrp[j++].s_addr &= maskp->s_addr; for (k = 0; k < j - 1; k++) { if (addrp[k].s_addr == addrp[j - 1].s_addr) { (*naddrs)--; j--; break; } } } } struct arptables_match * find_match(const char *name, enum arpt_tryload tryload) { struct arptables_match *ptr; for (ptr = arptables_matches; ptr; ptr = ptr->next) { if (strcmp(name, ptr->name) == 0) break; } if (ptr && !ptr->loaded) { if (tryload != DONT_LOAD) ptr->loaded = 1; else ptr = NULL; } if(!ptr && (tryload == LOAD_MUST_SUCCEED)) { exit_error(PARAMETER_PROBLEM, "Couldn't find match `%s'\n", name); } if (ptr) ptr->used = 1; return ptr; } static void parse_interface(const char *arg, char *vianame, unsigned char *mask) { int vialen = strlen(arg); unsigned int i; memset(mask, 0, IFNAMSIZ); memset(vianame, 0, IFNAMSIZ); if (vialen + 1 > IFNAMSIZ) exit_error(PARAMETER_PROBLEM, "interface name `%s' must be shorter than IFNAMSIZ" " (%i)", arg, IFNAMSIZ-1); strcpy(vianame, arg); if (vialen == 0) memset(mask, 0, IFNAMSIZ); else if (vianame[vialen - 1] == '+') { memset(mask, 0xFF, vialen - 1); memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1); /* Don't remove `+' here! -HW */ } else { /* Include nul-terminator in match */ memset(mask, 0xFF, vialen + 1); memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1); for (i = 0; vianame[i]; i++) { if (!isalnum(vianame[i]) && vianame[i] != '_' && vianame[i] != '.') { printf("Warning: wierd character in interface" " `%s' (No aliases, :, ! or *).\n", vianame); break; } } } } /* Can't be zero. */ static int parse_rulenumber(const char *rule) { unsigned int rulenum; if (string_to_number(rule, 1, INT_MAX, &rulenum) == -1) exit_error(PARAMETER_PROBLEM, "Invalid rule number `%s'", rule); return rulenum; } static const char * parse_target(const char *targetname) { const char *ptr; if (strlen(targetname) < 1) exit_error(PARAMETER_PROBLEM, "Invalid target name (too short)"); if (strlen(targetname)+1 > sizeof(arpt_chainlabel)) exit_error(PARAMETER_PROBLEM, "Invalid target name `%s' (%zu chars max)", targetname, sizeof(arpt_chainlabel)-1); for (ptr = targetname; *ptr; ptr++) if (isspace(*ptr)) exit_error(PARAMETER_PROBLEM, "Invalid target name `%s'", targetname); return targetname; } static char * addr_to_network(const struct in_addr *addr) { struct netent *net; if ((net = getnetbyaddr((long) ntohl(addr->s_addr), AF_INET)) != NULL) return (char *) net->n_name; return (char *) NULL; } char * addr_to_dotted(const struct in_addr *addrp) { static char buf[20]; const unsigned char *bytep; bytep = (const unsigned char *) &(addrp->s_addr); sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]); return buf; } char * addr_to_anyname(const struct in_addr *addr) { char *name; if ((name = addr_to_host(addr)) != NULL || (name = addr_to_network(addr)) != NULL) return name; return addr_to_dotted(addr); } char * mask_to_dotted(const struct in_addr *mask) { int i; static char buf[20]; uint32_t maskaddr, bits; maskaddr = ntohl(mask->s_addr); if (maskaddr == 0xFFFFFFFFL) /* we don't want to see "/32" */ return ""; i = 32; bits = 0xFFFFFFFEL; while (--i >= 0 && maskaddr != bits) bits <<= 1; if (i >= 0) sprintf(buf, "/%d", i); else /* mask was not a decent combination of 1's and 0's */ sprintf(buf, "/%s", addr_to_dotted(mask)); return buf; } int string_to_number(const char *s, unsigned int min, unsigned int max, unsigned int *ret) { long number; char *end; /* Handle hex, octal, etc. */ errno = 0; number = strtol(s, &end, 0); if (*end == '\0' && end != s) { /* we parsed a number, let's see if we want this */ if (errno != ERANGE && min <= number && number <= max) { *ret = number; return 0; } } return -1; } static void set_option(unsigned int *options, unsigned int option, uint16_t *invflg, int invert) { if (*options & option) exit_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed", opt2char(option)); *options |= option; if (invert) { unsigned int i; for (i = 0; 1 << i != option; i++); if (!inverse_for_options[i]) exit_error(PARAMETER_PROBLEM, "cannot have ! before -%c", opt2char(option)); *invflg |= inverse_for_options[i]; } } struct arptables_target * find_target(const char *name, enum arpt_tryload tryload) { struct arptables_target *ptr; /* Standard target? */ if (strcmp(name, "") == 0 || strcmp(name, ARPTC_LABEL_ACCEPT) == 0 || strcmp(name, ARPTC_LABEL_DROP) == 0 || strcmp(name, ARPTC_LABEL_QUEUE) == 0 || strcmp(name, ARPTC_LABEL_RETURN) == 0) name = "standard"; for (ptr = arptables_targets; ptr; ptr = ptr->next) { if (strcmp(name, ptr->name) == 0) break; } if (ptr && !ptr->loaded) { if (tryload != DONT_LOAD) ptr->loaded = 1; else ptr = NULL; } if(!ptr && (tryload == LOAD_MUST_SUCCEED)) { exit_error(PARAMETER_PROBLEM, "Couldn't find target `%s'\n", name); } if (ptr) ptr->used = 1; return ptr; } static struct option * merge_options(struct option *oldopts, const struct option *newopts, unsigned int *option_offset) { unsigned int num_old, num_new, i; struct option *merge; for (num_old = 0; oldopts[num_old].name; num_old++); for (num_new = 0; newopts[num_new].name; num_new++); global_option_offset += OPTION_OFFSET; *option_offset = global_option_offset; merge = malloc(sizeof(struct option) * (num_new + num_old + 1)); memcpy(merge, oldopts, num_old * sizeof(struct option)); for (i = 0; i < num_new; i++) { merge[num_old + i] = newopts[i]; merge[num_old + i].val += *option_offset; } memset(merge + num_old + num_new, 0, sizeof(struct option)); return merge; } void register_match(struct arptables_match *me) { struct arptables_match **i; if (strcmp(me->version, program_version) != 0) { fprintf(stderr, "%s: match `%s' v%s (I'm v%s).\n", program_name, me->name, me->version, program_version); exit(1); } if (find_match(me->name, DONT_LOAD)) { fprintf(stderr, "%s: match `%s' already registered.\n", program_name, me->name); exit(1); } if (me->size != ARPT_ALIGN(me->size)) { fprintf(stderr, "%s: match `%s' has invalid size %zu.\n", program_name, me->name, me->size); exit(1); } /* Append to list. */ for (i = &arptables_matches; *i; i = &(*i)->next); me->next = NULL; *i = me; me->m = NULL; me->mflags = 0; } void register_target(struct arptables_target *me) { if (strcmp(me->version, program_version) != 0) { fprintf(stderr, "%s: target `%s' v%s (I'm v%s).\n", program_name, me->name, me->version, program_version); exit(1); } if (find_target(me->name, DONT_LOAD)) { fprintf(stderr, "%s: target `%s' already registered.\n", program_name, me->name); exit(1); } if (me->size != ARPT_ALIGN(me->size)) { fprintf(stderr, "%s: target `%s' has invalid size %zu.\n", program_name, me->name, me->size); exit(1); } /* Prepend to list. */ me->next = arptables_targets; arptables_targets = me; me->t = NULL; me->tflags = 0; } static void print_num(uint64_t number, unsigned int format) { if (format & FMT_KILOMEGAGIGA) { if (number > 99999) { number = (number + 500) / 1000; if (number > 9999) { number = (number + 500) / 1000; if (number > 9999) { number = (number + 500) / 1000; if (number > 9999) { number = (number + 500) / 1000; printf(FMT("%4"PRIu64"T ","%"PRIu64"T "), number); } else printf(FMT("%4"PRIu64"G ","%"PRIu64"G "), number); } else printf(FMT("%4"PRIu64"M ","%"PRIu64"M "), number); } else printf(FMT("%4"PRIu64"K ","%"PRIu64"K "), number); } else printf(FMT("%5"PRIu64" ","%"PRIu64" "), number); } else printf(FMT("%8"PRIu64" ","%"PRIu64" "), number); } static void print_header(unsigned int format, const char *chain, arptc_handle_t *handle) { struct arpt_counters counters; const char *pol = arptc_get_policy(chain, &counters, handle); printf("Chain %s", chain); if (pol) { printf(" (policy %s", pol); if (!(format & FMT_NOCOUNTS)) { fputc(' ', stdout); print_num(counters.pcnt, (format|FMT_NOTABLE)); fputs("packets, ", stdout); print_num(counters.bcnt, (format|FMT_NOTABLE)); fputs("bytes", stdout); } printf(")\n"); } else { unsigned int refs; if (!arptc_get_references(&refs, chain, handle)) printf(" (ERROR obtaining refs)\n"); else printf(" (%u references)\n", refs); } /* I don't like this if (format & FMT_LINENUMBERS) printf(FMT("%-4s ", "%s "), "num"); if (!(format & FMT_NOCOUNTS)) { if (format & FMT_KILOMEGAGIGA) { printf(FMT("%5s ","%s "), "pkts"); printf(FMT("%5s ","%s "), "bytes"); } else { printf(FMT("%8s ","%s "), "pkts"); printf(FMT("%10s ","%s "), "bytes"); } } if (!(format & FMT_NOTARGET)) printf(FMT("%-9s ","%s "), "target"); fputs(" prot ", stdout); if (format & FMT_OPTIONS) fputs("opt", stdout); if (format & FMT_VIA) { printf(FMT(" %-6s ","%s "), "in"); printf(FMT("%-6s ","%s "), "out"); } printf(FMT(" %-19s ","%s "), "source"); printf(FMT(" %-19s "," %s "), "destination"); printf("\n"); */ } /* static int print_match(const struct arpt_entry_match *m, const struct arpt_arp *arp, int numeric) { struct arptables_match *match = find_match(m->u.user.name, TRY_LOAD); if (match) { if (match->print) match->print(arp, m, numeric); else printf("%s ", match->name); } else { if (m->u.user.name[0]) printf("UNKNOWN match `%s' ", m->u.user.name); } */ /* Don't stop iterating. */ /* return 0; } */ /* e is called `fw' here for hysterical raisins */ static void print_firewall(const struct arpt_entry *fw, const char *targname, unsigned int num, unsigned int format, const arptc_handle_t handle) { struct arptables_target *target = NULL; const struct arpt_entry_target *t; char buf[BUFSIZ]; int i; char iface[IFNAMSIZ+2]; int print_iface = 0; if (!arptc_is_chain(targname, handle)) target = find_target(targname, TRY_LOAD); else target = find_target(ARPT_STANDARD_TARGET, LOAD_MUST_SUCCEED); t = arpt_get_target((struct arpt_entry *)fw); if (format & FMT_LINENUMBERS) printf("%u ", num+1); if (!(format & FMT_NOTARGET) && targname[0] != '\0') printf("-j %s ", targname); iface[0] = '\0'; if (fw->arp.iniface[0] != '\0') { strcat(iface, fw->arp.iniface); print_iface = 1; } else if (format & FMT_VIA) { print_iface = 1; if (format & FMT_NUMERIC) strcat(iface, "*"); else strcat(iface, "any"); } if (print_iface) printf("%s-i %s ", fw->arp.invflags & ARPT_INV_VIA_IN ? "! ": "", iface); print_iface = 0; iface[0] = '\0'; if (fw->arp.outiface[0] != '\0') { strcat(iface, fw->arp.outiface); print_iface = 1; } else if (format & FMT_VIA) { print_iface = 1; if (format & FMT_NUMERIC) strcat(iface, "*"); else strcat(iface, "any"); } if (print_iface) printf("%s-o %s ", fw->arp.invflags & ARPT_INV_VIA_OUT ? "! " : "", iface); if (fw->arp.smsk.s_addr != 0L) { printf("%s", fw->arp.invflags & ARPT_INV_SRCIP ? "! " : ""); if (format & FMT_NUMERIC) sprintf(buf, "%s", addr_to_dotted(&(fw->arp.src))); else sprintf(buf, "%s", addr_to_anyname(&(fw->arp.src))); strncat(buf, mask_to_dotted(&(fw->arp.smsk)), sizeof(buf) - strlen(buf) -1); printf("-s %s ", buf); } for (i = 0; i < ARPT_DEV_ADDR_LEN_MAX; i++) if (fw->arp.src_devaddr.mask[i] != 0) break; if (i == ARPT_DEV_ADDR_LEN_MAX) goto after_devsrc; printf("%s", fw->arp.invflags & ARPT_INV_SRCDEVADDR ? "! " : ""); printf("--src-mac "); print_mac_and_mask((unsigned char *)fw->arp.src_devaddr.addr, (unsigned char *)fw->arp.src_devaddr.mask, ETH_ALEN); printf(" "); after_devsrc: if (fw->arp.tmsk.s_addr != 0L) { printf("%s",fw->arp.invflags & ARPT_INV_TGTIP ? "! " : ""); if (format & FMT_NUMERIC) sprintf(buf, "%s", addr_to_dotted(&(fw->arp.tgt))); else sprintf(buf, "%s", addr_to_anyname(&(fw->arp.tgt))); strncat(buf, mask_to_dotted(&(fw->arp.tmsk)), sizeof(buf) - strlen(buf) -1); printf("-d %s ", buf); } for (i = 0; i arp.tgt_devaddr.mask[i] != 0) break; if (i == ARPT_DEV_ADDR_LEN_MAX) goto after_devdst; printf("%s",fw->arp.invflags & ARPT_INV_TGTDEVADDR ? "! " : ""); printf("--dst-mac "); print_mac_and_mask((unsigned char *)fw->arp.tgt_devaddr.addr, (unsigned char *)fw->arp.tgt_devaddr.mask, ETH_ALEN); printf(" "); after_devdst: if (fw->arp.arhln_mask != 0) { printf("%s",fw->arp.invflags & ARPT_INV_ARPHLN ? "! " : ""); printf("--h-length %d", fw->arp.arhln); if (fw->arp.arhln_mask != 255) printf("/%d", fw->arp.arhln_mask); printf(" "); } if (fw->arp.arpop_mask != 0) { int tmp = ntohs(fw->arp.arpop); printf("%s",fw->arp.invflags & ARPT_INV_ARPOP ? "! " : ""); if (tmp <= NUMOPCODES && !(format & FMT_NUMERIC)) printf("--opcode %s", opcodes[tmp-1]); else printf("--opcode %d", tmp); if (fw->arp.arpop_mask != 65535) printf("/%d", ntohs(fw->arp.arpop_mask)); printf(" "); } if (fw->arp.arhrd_mask != 0) { uint16_t tmp = ntohs(fw->arp.arhrd); printf("%s", fw->arp.invflags & ARPT_INV_ARPHRD ? "! " : ""); if (tmp == 1 && !(format & FMT_NUMERIC)) printf("--h-type %s", "Ethernet"); else printf("--h-type %u", tmp); if (fw->arp.arhrd_mask != 65535) printf("/%d", ntohs(fw->arp.arhrd_mask)); printf(" "); } if (fw->arp.arpro_mask != 0) { int tmp = ntohs(fw->arp.arpro); printf("%s", fw->arp.invflags & ARPT_INV_ARPPRO ? "! " : ""); if (tmp == 0x0800 && !(format & FMT_NUMERIC)) printf("--proto-type %s", "IPv4"); else printf("--proto-type 0x%x", tmp); if (fw->arp.arpro_mask != 65535) printf("/%x", ntohs(fw->arp.arpro_mask)); printf(" "); } /* FIXME ARPT_MATCH_ITERATE(fw, print_match, &fw->ip, format & FMT_NUMERIC); */ if (target) { if (target->print) /* Print the target information. */ target->print(&fw->arp, t, format & FMT_NUMERIC); } else if (t->u.target_size != sizeof(*t)) printf("[%zu bytes of unknown target data] ", t->u.target_size - sizeof(*t)); if (!(format & FMT_NOCOUNTS)) { printf(", pcnt="); print_num(fw->counters.pcnt, format); printf("-- bcnt="); print_num(fw->counters.bcnt, format); } if (!(format & FMT_NONEWLINE)) fputc('\n', stdout); } static void print_firewall_line(const struct arpt_entry *fw, const arptc_handle_t h) { struct arpt_entry_target *t; t = arpt_get_target((struct arpt_entry *)fw); print_firewall(fw, t->u.user.name, 0, FMT_PRINT_RULE, h); } static int append_entry(const arpt_chainlabel chain, struct arpt_entry *fw, unsigned int nsaddrs, const struct in_addr saddrs[], unsigned int ndaddrs, const struct in_addr daddrs[], int verbose, arptc_handle_t *handle) { unsigned int i, j; int ret = 1; for (i = 0; i < nsaddrs; i++) { fw->arp.src.s_addr = saddrs[i].s_addr; for (j = 0; j < ndaddrs; j++) { fw->arp.tgt.s_addr = daddrs[j].s_addr; if (verbose) print_firewall_line(fw, *handle); ret &= arptc_append_entry(chain, fw, handle); } } return ret; } static int replace_entry(const arpt_chainlabel chain, struct arpt_entry *fw, unsigned int rulenum, const struct in_addr *saddr, const struct in_addr *daddr, int verbose, arptc_handle_t *handle) { fw->arp.src.s_addr = saddr->s_addr; fw->arp.tgt.s_addr = daddr->s_addr; if (verbose) print_firewall_line(fw, *handle); return arptc_replace_entry(chain, fw, rulenum, handle); } static int insert_entry(const arpt_chainlabel chain, struct arpt_entry *fw, unsigned int rulenum, unsigned int nsaddrs, const struct in_addr saddrs[], unsigned int ndaddrs, const struct in_addr daddrs[], int verbose, arptc_handle_t *handle) { unsigned int i, j; int ret = 1; for (i = 0; i < nsaddrs; i++) { fw->arp.src.s_addr = saddrs[i].s_addr; for (j = 0; j < ndaddrs; j++) { fw->arp.tgt.s_addr = daddrs[j].s_addr; if (verbose) print_firewall_line(fw, *handle); ret &= arptc_insert_entry(chain, fw, rulenum, handle); } } return ret; } static unsigned char * make_delete_mask(struct arpt_entry *fw) { /* Establish mask for comparison */ unsigned int size; struct arptables_match *m; unsigned char *mask, *mptr; size = sizeof(struct arpt_entry); for (m = arptables_matches; m; m = m->next) { if (!m->used) continue; size += ARPT_ALIGN(sizeof(struct arpt_entry_match)) + m->size; } mask = fw_calloc(1, size + ARPT_ALIGN(sizeof(struct arpt_entry_target)) + arptables_targets->size); memset(mask, 0xFF, sizeof(struct arpt_entry)); mptr = mask + sizeof(struct arpt_entry); for (m = arptables_matches; m; m = m->next) { if (!m->used) continue; memset(mptr, 0xFF, ARPT_ALIGN(sizeof(struct arpt_entry_match)) + m->userspacesize); mptr += ARPT_ALIGN(sizeof(struct arpt_entry_match)) + m->size; } memset(mptr, 0xFF, ARPT_ALIGN(sizeof(struct arpt_entry_target)) + arptables_targets->userspacesize); return mask; } static int delete_entry(const arpt_chainlabel chain, struct arpt_entry *fw, unsigned int nsaddrs, const struct in_addr saddrs[], unsigned int ndaddrs, const struct in_addr daddrs[], int verbose, arptc_handle_t *handle) { unsigned int i, j; int ret = 1; unsigned char *mask; mask = make_delete_mask(fw); for (i = 0; i < nsaddrs; i++) { fw->arp.src.s_addr = saddrs[i].s_addr; for (j = 0; j < ndaddrs; j++) { fw->arp.tgt.s_addr = daddrs[j].s_addr; if (verbose) print_firewall_line(fw, *handle); ret &= arptc_delete_entry(chain, fw, mask, handle); } } return ret; } int for_each_chain(int (*fn)(const arpt_chainlabel, int, arptc_handle_t *), int verbose, int builtinstoo, arptc_handle_t *handle) { int ret = 1; const char *chain; char *chains; unsigned int i, chaincount = 0; chain = arptc_first_chain(handle); while (chain) { chaincount++; chain = arptc_next_chain(handle); } chains = fw_malloc(sizeof(arpt_chainlabel) * chaincount); i = 0; chain = arptc_first_chain(handle); while (chain) { strcpy(chains + i*sizeof(arpt_chainlabel), chain); i++; chain = arptc_next_chain(handle); } for (i = 0; i < chaincount; i++) { if (!builtinstoo && arptc_builtin(chains + i*sizeof(arpt_chainlabel), *handle)) continue; ret &= fn(chains + i*sizeof(arpt_chainlabel), verbose, handle); } free(chains); return ret; } int flush_entries(const arpt_chainlabel chain, int verbose, arptc_handle_t *handle) { if (!chain) return for_each_chain(flush_entries, verbose, 1, handle); if (verbose) fprintf(stdout, "Flushing chain `%s'\n", chain); return arptc_flush_entries(chain, handle); } static int zero_entries(const arpt_chainlabel chain, int verbose, arptc_handle_t *handle) { if (!chain) return for_each_chain(zero_entries, verbose, 1, handle); if (verbose) fprintf(stdout, "Zeroing chain `%s'\n", chain); return arptc_zero_entries(chain, handle); } int delete_chain(const arpt_chainlabel chain, int verbose, arptc_handle_t *handle) { if (!chain) return for_each_chain(delete_chain, verbose, 0, handle); if (verbose) fprintf(stdout, "Deleting chain `%s'\n", chain); return arptc_delete_chain(chain, handle); } static int list_entries(const arpt_chainlabel chain, int verbose, int numeric, int expanded, int linenumbers, arptc_handle_t *handle) { int found = 0; unsigned int format; const char *this; format = FMT_OPTIONS; if (!verbose) format |= FMT_NOCOUNTS; else format |= FMT_VIA; if (numeric) format |= FMT_NUMERIC; if (!expanded) format |= FMT_KILOMEGAGIGA; if (linenumbers) format |= FMT_LINENUMBERS; for (this = arptc_first_chain(handle); this; this = arptc_next_chain(handle)) { const struct arpt_entry *i; unsigned int num; if (chain && strcmp(chain, this) != 0) continue; if (found) printf("\n"); print_header(format, this, handle); i = arptc_first_rule(this, handle); num = 0; while (i) { print_firewall(i, arptc_get_target(i, handle), num++, format, *handle); i = arptc_next_rule(i, handle); } found = 1; } errno = ENOENT; return found; } static char *get_modprobe(void) { int procfile; char *ret; procfile = open(PROC_SYS_MODPROBE, O_RDONLY); if (procfile < 0) return NULL; ret = malloc(1024); if (ret) { int read_bytes = read(procfile, ret, 1024); switch (read_bytes) { case -1: goto fail; case 1024: goto fail; /* Partial read. Wierd */ } ret[read_bytes] = '\0'; if (ret[strlen(ret)-1]=='\n') ret[strlen(ret)-1]=0; close(procfile); return ret; } fail: free(ret); close(procfile); return NULL; } int arptables_insmod(const char *modname, const char *modprobe) { char *buf = NULL; char *argv[3]; /* If they don't explicitly set it, read out of kernel */ if (!modprobe) { buf = get_modprobe(); if (!buf) return -1; modprobe = buf; } switch (fork()) { case 0: argv[0] = (char *)modprobe; argv[1] = (char *)modname; argv[2] = NULL; execv(argv[0], argv); /* not usually reached */ exit(0); case -1: return -1; default: /* parent */ wait(NULL); } free(buf); return 0; } static struct arpt_entry * generate_entry(const struct arpt_entry *fw, struct arptables_match *matches, struct arpt_entry_target *target) { unsigned int size; /* struct arptables_match *m; */ struct arpt_entry *e; size = sizeof(struct arpt_entry); /* FIXME for (m = matches; m; m = m->next) { if (!m->used) continue; size += m->m->u.match_size; } */ e = fw_malloc(size + target->u.target_size); *e = *fw; e->target_offset = size; e->next_offset = size + target->u.target_size; size = 0; /* FIXME for (m = matches; m; m = m->next) { if (!m->used) continue; memcpy(e->elems + size, m->m, m->m->u.match_size); size += m->m->u.match_size; } */ memcpy(e->elems + size, target, target->u.target_size); return e; } int do_command(int argc, char *argv[], char **table, arptc_handle_t *handle) { struct arpt_entry fw, *e = NULL; int invert = 0; unsigned int nsaddrs = 0, ndaddrs = 0; struct in_addr *saddrs = NULL, *daddrs = NULL; int c, verbose = 0; const char *chain = NULL; const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL; const char *policy = NULL, *newname = NULL; unsigned int rulenum = 0, options = 0, command = 0; const char *pcnt = NULL, *bcnt = NULL; int ret = 1; /* struct arptables_match *m;*/ struct arptables_target *target = NULL; struct arptables_target *t; const char *jumpto = ""; char *protocol = NULL; const char *modprobe = NULL; /* first figure out if this is a 2.6 or a 2.4 kernel */ *handle = arptc_init(*table); if (!*handle) { arptables_insmod("arp_tables", modprobe); *handle = arptc_init(*table); if (!*handle) { RUNTIME_NF_ARP_NUMHOOKS = 2; *handle = arptc_init(*table); if (!*handle) { exit_error(VERSION_PROBLEM, "can't initialize arptables table `%s': %s", *table, arptc_strerror(errno)); } } } memset(&fw, 0, sizeof(fw)); opts = original_opts; global_option_offset = 0; /* re-set optind to 0 in case do_command gets called * a second time */ optind = 0; /* clear mflags in case do_command gets called a second time * (we clear the global list of all matches for security)*/ /* for (m = arptables_matches; m; m = m->next) { m->mflags = 0; m->used = 0; }*/ for (t = arptables_targets; t; t = t->next) { t->tflags = 0; t->used = 0; } /* Suppress error messages: we may add new options if we demand-load a protocol. */ opterr = 0; while ((c = getopt_long(argc, argv, "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:l:i:vnt:m:c:", opts, NULL)) != -1) { switch (c) { /* * Command selection */ case 'A': add_command(&command, CMD_APPEND, CMD_NONE, invert); chain = optarg; break; case 'D': add_command(&command, CMD_DELETE, CMD_NONE, invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') { rulenum = parse_rulenumber(argv[optind++]); command = CMD_DELETE_NUM; } break; case 'R': add_command(&command, CMD_REPLACE, CMD_NONE, invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') rulenum = parse_rulenumber(argv[optind++]); else exit_error(PARAMETER_PROBLEM, "-%c requires a rule number", cmd2char(CMD_REPLACE)); break; case 'I': add_command(&command, CMD_INSERT, CMD_NONE, invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') rulenum = parse_rulenumber(argv[optind++]); else rulenum = 1; break; case 'L': add_command(&command, CMD_LIST, CMD_ZERO, invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') chain = argv[optind++]; break; case 'F': add_command(&command, CMD_FLUSH, CMD_NONE, invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') chain = argv[optind++]; break; case 'Z': add_command(&command, CMD_ZERO, CMD_LIST, invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') chain = argv[optind++]; break; case 'N': if (optarg && *optarg == '-') exit_error(PARAMETER_PROBLEM, "chain name not allowed to start " "with `-'\n"); if (find_target(optarg, TRY_LOAD)) exit_error(PARAMETER_PROBLEM, "chain name may not clash " "with target name\n"); add_command(&command, CMD_NEW_CHAIN, CMD_NONE, invert); chain = optarg; break; case 'X': add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') chain = argv[optind++]; break; case 'E': add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') newname = argv[optind++]; else exit_error(PARAMETER_PROBLEM, "-%c requires old-chain-name and " "new-chain-name", cmd2char(CMD_RENAME_CHAIN)); break; case 'P': add_command(&command, CMD_SET_POLICY, CMD_NONE, invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') policy = argv[optind++]; else exit_error(PARAMETER_PROBLEM, "-%c requires a chain and a policy", cmd2char(CMD_SET_POLICY)); break; case 'h': if (!optarg) optarg = argv[optind]; /* arptables -p icmp -h */ if (!arptables_matches && protocol) find_match(protocol, TRY_LOAD); exit_printhelp(); case 's': check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_S_IP, &fw.arp.invflags, invert); shostnetworkmask = argv[optind-1]; break; case 'd': check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_D_IP, &fw.arp.invflags, invert); dhostnetworkmask = argv[optind-1]; break; case 2:/* src-mac */ check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_S_MAC, &fw.arp.invflags, invert); if (getmac_and_mask(argv[optind - 1], fw.arp.src_devaddr.addr, fw.arp.src_devaddr.mask)) exit_error(PARAMETER_PROBLEM, "Problem with specified " "source mac"); break; case 3:/* dst-mac */ check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_D_MAC, &fw.arp.invflags, invert); if (getmac_and_mask(argv[optind - 1], fw.arp.tgt_devaddr.addr, fw.arp.tgt_devaddr.mask)) exit_error(PARAMETER_PROBLEM, "Problem with specified " "destination mac"); break; case 'l':/* hardware length */ check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_H_LENGTH, &fw.arp.invflags, invert); getlength_and_mask(argv[optind - 1], &fw.arp.arhln, &fw.arp.arhln_mask); break; case 8:/* protocol length */ exit_error(PARAMETER_PROBLEM, "not supported"); /* check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_P_LENGTH, &fw.arp.invflags, invert); getlength_and_mask(argv[optind - 1], &fw.arp.arpln, &fw.arp.arpln_mask); break; */ case 4:/* opcode */ check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_OPCODE, &fw.arp.invflags, invert); if (get16_and_mask(argv[optind - 1], &fw.arp.arpop, &fw.arp.arpop_mask, 10)) { int i; for (i = 0; i < NUMOPCODES; i++) if (!strcasecmp(opcodes[i], optarg)) break; if (i == NUMOPCODES) exit_error(PARAMETER_PROBLEM, "Problem with specified opcode"); fw.arp.arpop = htons(i+1); } break; case 5:/* h-type */ check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_H_TYPE, &fw.arp.invflags, invert); if (get16_and_mask(argv[optind - 1], &fw.arp.arhrd, &fw.arp.arhrd_mask, 16)) { if (strcasecmp(argv[optind-1], "Ethernet")) exit_error(PARAMETER_PROBLEM, "Problem with specified hardware type"); fw.arp.arhrd = htons(1); } break; case 6:/* proto-type */ check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_P_TYPE, &fw.arp.invflags, invert); if (get16_and_mask(argv[optind - 1], &fw.arp.arpro, &fw.arp.arpro_mask, 0)) { if (strcasecmp(argv[optind-1], "ipv4")) exit_error(PARAMETER_PROBLEM, "Problem with specified protocol type"); fw.arp.arpro = htons(0x800); } break; case 'j': set_option(&options, OPT_JUMP, &fw.arp.invflags, invert); jumpto = parse_target(optarg); /* TRY_LOAD (may be chain name) */ target = find_target(jumpto, TRY_LOAD); if (target) { size_t size; size = ARPT_ALIGN(sizeof(struct arpt_entry_target)) + target->size; target->t = fw_calloc(1, size); target->t->u.target_size = size; strncpy(target->t->u.user.name, jumpto, sizeof(target->t->u.user.name) - 1); target->t->u.user.revision = target->revision; /* target->init(target->t, &fw.nfcache); */ target->init(target->t); opts = merge_options(opts, target->extra_opts, &target->option_offset); } break; case 'i': check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_VIANAMEIN, &fw.arp.invflags, invert); parse_interface(argv[optind-1], fw.arp.iniface, fw.arp.iniface_mask); /* fw.nfcache |= NFC_IP_IF_IN; */ break; case 'o': check_inverse(optarg, &invert, &optind, argc); set_option(&options, OPT_VIANAMEOUT, &fw.arp.invflags, invert); parse_interface(argv[optind-1], fw.arp.outiface, fw.arp.outiface_mask); /* fw.nfcache |= NFC_IP_IF_OUT; */ break; case 'v': if (!verbose) set_option(&options, OPT_VERBOSE, &fw.arp.invflags, invert); verbose++; break; case 'm': /*{ size_t size; if (invert) exit_error(PARAMETER_PROBLEM, "unexpected ! flag before --match"); m = find_match(optarg, LOAD_MUST_SUCCEED); size = ARPT_ALIGN(sizeof(struct arpt_entry_match)) + m->size; m->m = fw_calloc(1, size); m->m->u.match_size = size; strcpy(m->m->u.user.name, m->name); m->init(m->m, &fw.nfcache); opts = merge_options(opts, m->extra_opts, &m->option_offset); }*/ break; case 'n': set_option(&options, OPT_NUMERIC, &fw.arp.invflags, invert); break; case 't': if (invert) exit_error(PARAMETER_PROBLEM, "unexpected ! flag before --table"); *table = argv[optind-1]; break; case 'V': if (invert) printf("Not %s ;-)\n", program_version); else printf("%s v%s\n", program_name, program_version); exit(0); case '0': set_option(&options, OPT_LINENUMBERS, &fw.arp.invflags, invert); break; case 'M': modprobe = optarg; break; case 'c': set_option(&options, OPT_COUNTERS, &fw.arp.invflags, invert); pcnt = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') bcnt = argv[optind++]; else exit_error(PARAMETER_PROBLEM, "-%c requires packet and byte counter", opt2char(OPT_COUNTERS)); if (sscanf(pcnt, "%"PRIu64, (uint64_t *)&fw.counters.pcnt) != 1) exit_error(PARAMETER_PROBLEM, "-%c packet counter not numeric", opt2char(OPT_COUNTERS)); if (sscanf(bcnt, "%"PRIu64, (uint64_t *)&fw.counters.bcnt) != 1) exit_error(PARAMETER_PROBLEM, "-%c byte counter not numeric", opt2char(OPT_COUNTERS)); break; case 1: /* non option */ if (optarg[0] == '!' && optarg[1] == '\0') { if (invert) exit_error(PARAMETER_PROBLEM, "multiple consecutive ! not" " allowed"); invert = TRUE; optarg[0] = '\0'; continue; } printf("Bad argument `%s'\n", optarg); exit_tryhelp(2); default: /* FIXME: This scheme doesn't allow two of the same matches --RR */ if (!target || !(target->parse(c - target->option_offset, argv, invert, &target->tflags, &fw, &target->t))) { /* for (m = arptables_matches; m; m = m->next) { if (!m->used) continue; if (m->parse(c - m->option_offset, argv, invert, &m->mflags, &fw, &fw.nfcache, &m->m)) break; } */ /* If you listen carefully, you can actually hear this code suck. */ /* some explanations (after four different bugs * in 3 different releases): If we encountere a * parameter, that has not been parsed yet, * it's not an option of an explicitly loaded * match or a target. However, we support * implicit loading of the protocol match * extension. '-p tcp' means 'l4 proto 6' and * at the same time 'load tcp protocol match on * demand if we specify --dport'. * * To make this work, we need to make sure: * - the parameter has not been parsed by * a match (m above) * - a protocol has been specified * - the protocol extension has not been * loaded yet, or is loaded and unused * [think of arptables-restore!] * - the protocol extension can be successively * loaded */ /* if (m == NULL && protocol && (!find_proto(protocol, DONT_LOAD, options&OPT_NUMERIC) || (find_proto(protocol, DONT_LOAD, options&OPT_NUMERIC) && (proto_used == 0)) ) && (m = find_proto(protocol, TRY_LOAD, options&OPT_NUMERIC))) { Try loading protocol */ /* size_t size; proto_used = 1; size = ARPT_ALIGN(sizeof(struct arpt_entry_match)) + m->size; m->m = fw_calloc(1, size); m->m->u.match_size = size; strcpy(m->m->u.user.name, m->name); m->init(m->m, &fw.nfcache); opts = merge_options(opts, m->extra_opts, &m->option_offset); optind--; continue; } if (!m) exit_error(PARAMETER_PROBLEM, "Unknown arg `%s'", argv[optind-1]); */ } } invert = FALSE; } /* for (m = arptables_matches; m; m = m->next) { if (!m->used) continue; m->final_check(m->mflags); } */ if (target) target->final_check(target->tflags); /* Fix me: must put inverse options checking here --MN */ if (optind < argc) exit_error(PARAMETER_PROBLEM, "unknown arguments found on commandline"); if (!command) exit_error(PARAMETER_PROBLEM, "no command specified"); if (invert) exit_error(PARAMETER_PROBLEM, "nothing appropriate following !"); if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) { if (!(options & OPT_D_IP)) dhostnetworkmask = "0.0.0.0/0"; if (!(options & OPT_S_IP)) shostnetworkmask = "0.0.0.0/0"; } if (shostnetworkmask) parse_hostnetworkmask(shostnetworkmask, &saddrs, &(fw.arp.smsk), &nsaddrs); if (dhostnetworkmask) parse_hostnetworkmask(dhostnetworkmask, &daddrs, &(fw.arp.tmsk), &ndaddrs); if ((nsaddrs > 1 || ndaddrs > 1) && (fw.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP))) exit_error(PARAMETER_PROBLEM, "! not allowed with multiple" " source or destination IP addresses"); if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1)) exit_error(PARAMETER_PROBLEM, "Replacement rule does not " "specify a unique address"); generic_opt_check(command, options); if (chain && strlen(chain) > ARPT_FUNCTION_MAXNAMELEN) exit_error(PARAMETER_PROBLEM, "chain name `%s' too long (must be under %i chars)", chain, ARPT_FUNCTION_MAXNAMELEN); /* only allocate handle if we weren't called with a handle */ if (!*handle) *handle = arptc_init(*table); if (!*handle) { /* try to insmod the module if arptc_init failed */ arptables_insmod("arp_tables", modprobe); *handle = arptc_init(*table); } if (!*handle) exit_error(VERSION_PROBLEM, "can't initialize arptables table `%s': %s", *table, arptc_strerror(errno)); if (command == CMD_APPEND || command == CMD_DELETE || command == CMD_INSERT || command == CMD_REPLACE) { if (strcmp(chain, "PREROUTING") == 0 || strcmp(chain, "INPUT") == 0) { /* -o not valid with incoming packets. */ if (options & OPT_VIANAMEOUT) exit_error(PARAMETER_PROBLEM, "Can't use -%c with %s\n", opt2char(OPT_VIANAMEOUT), chain); } if (strcmp(chain, "POSTROUTING") == 0 || strcmp(chain, "OUTPUT") == 0) { /* -i not valid with outgoing packets */ if (options & OPT_VIANAMEIN) exit_error(PARAMETER_PROBLEM, "Can't use -%c with %s\n", opt2char(OPT_VIANAMEIN), chain); } if (target && arptc_is_chain(jumpto, *handle)) { printf("Warning: using chain %s, not extension\n", jumpto); target = NULL; } /* If they didn't specify a target, or it's a chain name, use standard. */ if (!target && (strlen(jumpto) == 0 || arptc_is_chain(jumpto, *handle))) { size_t size; target = find_target(ARPT_STANDARD_TARGET, LOAD_MUST_SUCCEED); size = sizeof(struct arpt_entry_target) + target->size; target->t = fw_calloc(1, size); target->t->u.target_size = size; strcpy(target->t->u.user.name, jumpto); target->t->u.user.revision = target->revision; target->init(target->t); } if (!target) { /* it is no chain, and we can't load a plugin. * We cannot know if the plugin is corrupt, non * existant OR if the user just misspelled a * chain. */ find_target(jumpto, LOAD_MUST_SUCCEED); } else { e = generate_entry(&fw, arptables_matches, target->t); } } switch (command) { case CMD_APPEND: ret = append_entry(chain, e, nsaddrs, saddrs, ndaddrs, daddrs, options&OPT_VERBOSE, handle); break; case CMD_DELETE: ret = delete_entry(chain, e, nsaddrs, saddrs, ndaddrs, daddrs, options&OPT_VERBOSE, handle); break; case CMD_DELETE_NUM: ret = arptc_delete_num_entry(chain, rulenum - 1, handle); break; case CMD_REPLACE: ret = replace_entry(chain, e, rulenum - 1, saddrs, daddrs, options&OPT_VERBOSE, handle); break; case CMD_INSERT: ret = insert_entry(chain, e, rulenum - 1, nsaddrs, saddrs, ndaddrs, daddrs, options&OPT_VERBOSE, handle); break; case CMD_LIST: ret = list_entries(chain, options&OPT_VERBOSE, options&OPT_NUMERIC, /*options&OPT_EXPANDED*/0, options&OPT_LINENUMBERS, handle); break; case CMD_FLUSH: ret = flush_entries(chain, options&OPT_VERBOSE, handle); break; case CMD_ZERO: ret = zero_entries(chain, options&OPT_VERBOSE, handle); break; case CMD_LIST|CMD_ZERO: ret = list_entries(chain, options&OPT_VERBOSE, options&OPT_NUMERIC, /*options&OPT_EXPANDED*/0, options&OPT_LINENUMBERS, handle); if (ret) ret = zero_entries(chain, options&OPT_VERBOSE, handle); break; case CMD_NEW_CHAIN: ret = arptc_create_chain(chain, handle); break; case CMD_DELETE_CHAIN: ret = delete_chain(chain, options&OPT_VERBOSE, handle); break; case CMD_RENAME_CHAIN: ret = arptc_rename_chain(chain, newname, handle); break; case CMD_SET_POLICY: ret = arptc_set_policy(chain, policy, NULL, handle); break; default: /* We should never reach this... */ exit_tryhelp(2); } if (verbose > 1) dump_entries(*handle); return ret; } arptables-0.0.5/arptables-standalone.c0000644000175000017500000000342713571215622016726 0ustar pablopablo/* * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au * * Based on the ipchains code by Paul Russell and Michael Neuling * * (C) 2000-2002 by the netfilter coreteam : * Paul 'Rusty' Russell * Marc Boucher * James Morris * Harald Welte * Jozsef Kadlecsik * * arptables -- IP firewall administration for kernels with * firewall table (aimed for the 2.3 kernels) * * See the accompanying manual page arptables(8) for information * about proper usage of this program. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include int main(int argc, char *argv[]) { int ret; char *table = "filter"; arptc_handle_t handle = NULL; program_name = "arptables"; /* init_extensions(); */ ret = do_command(argc, argv, &table, &handle); if (ret) ret = arptc_commit(&handle); if (!ret) fprintf(stderr, "arptables: %s\n", arptc_strerror(errno)); exit(!ret); } arptables-0.0.5/arptables-save.80000644000175000017500000000256613571215622015464 0ustar pablopablo.TH ARPTABLES-SAVE 8 "Nov 07, 2013" "" "" .\" .\" Man page written by Jesper Dangaard Brouer based on a .\" Man page written by Harald Welte .\" It is based on the iptables-save man page. .\" .\" This program is free software; you can redistribute it and/or modify .\" it under the terms of the GNU General Public License as published by .\" the Free Software Foundation; either version 2 of the License, or .\" (at your option) any later version. .\" .\" This program is distributed in the hope that it will be useful, .\" but WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the .\" GNU General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" along with this program; if not, write to the Free Software .\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. .\" .\" .SH NAME arptables-save \(em dump arptables rules to stdout .SH SYNOPSIS \fBarptables\-save .SH DESCRIPTION .PP .B arptables-save is used to dump the contents of an ARP Table in easily parseable format to STDOUT. Use I/O-redirection provided by your shell to write to a file. .SH BUGS None known as of arptables-0.0.4 release .SH AUTHOR Jesper Dangaard Brouer .SH SEE ALSO \fBarptables\-restore\fP(8), \fBarptables\fP(8) .PP arptables-0.0.5/arptables-save0000644000175000017500000000234413571215622015310 0ustar pablopablo#!/usr/bin/perl -w # # # A script that generates text output of the arptables rules. # Similar to iptables-save. use strict; my $table; my $tool = "__EXEC_PATH__/arptables"; # ======================================================== # Process filter table # ======================================================== sub process_table { my $chain = ""; my $rules = ""; my $chains = ""; my $custom_chains = ""; my $line = ""; foreach $line (split("\n",$_[0])) { if ($line =~ m/Chain\s(.*?)\s\(policy\s(.*?)\)/) { $chains = $chains . ":$1 $2\n"; $chain = $1; next; } if ($line =~ m/Chain\s(.*?)\s\(/) { $custom_chains = $custom_chains . ":$1 -\n"; $chain = $1; next; } if ($line =~ m/^$/) { next; } $rules = $rules . "-A $chain $line\n"; } print "*filter\n"; print $chains; print $custom_chains; print $rules; print "\n"; } # ======================================================== unless (-x "$tool") { print "ERROR: Tool $tool isn't executable"; exit -1; }; $table =`$tool -t filter -L -n`; unless ($? == 0) { print $table; exit -1 }; &process_table($table); arptables-0.0.5/arptables-restore.80000644000175000017500000000273513571215622016207 0ustar pablopablo.TH ARPTABLES-RESTORE 8 "Nov 07, 2013" "" "" .\" .\" Man page written by Jesper Dangaard Brouer based on a .\" Man page written by Harald Welte .\" It is based on the iptables-restore man page. .\" .\" This program is free software; you can redistribute it and/or modify .\" it under the terms of the GNU General Public License as published by .\" the Free Software Foundation; either version 2 of the License, or .\" (at your option) any later version. .\" .\" This program is distributed in the hope that it will be useful, .\" but WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the .\" GNU General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" along with this program; if not, write to the Free Software .\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. .\" .\" .SH NAME arptables-restore \(em Restore ARP Tables .SH SYNOPSIS \fBarptables\-restore .SH DESCRIPTION .PP .B arptables-restore is used to restore ARP Tables from data specified on STDIN or via a file as first argument. Use I/O redirection provided by your shell to read from a file .TP .B arptables-restore flushes (deletes) all previous contents of the respective ARP Table. .SH BUGS None known as of arptables-0.0.4 release .SH AUTHOR Jesper Dangaard Brouer .SH SEE ALSO \fBarptables\-save\fP(8), \fBarptables\fP(8) .PP arptables-0.0.5/arptables-restore0000644000175000017500000000322313571215622016032 0ustar pablopablo#!/usr/bin/perl -w # A script that imports text arptables rules. Similar to iptables-restore. use strict; my $tool = "__EXEC_PATH__/arptables"; my $table; my $rc; my $line; # ============================== # clear_arptables # - sets policy to accept # - flushes chains # - removes custom chains # ============================== sub clear_arptables { $rc = `$tool -P INPUT ACCEPT`; unless($? == 0) { print "ERROR: $rc\n"; exit -1 }; $rc = `$tool -P FORWARD ACCEPT`; unless($? == 0) { print "ERROR: $rc\n"; exit -1 }; $rc = `$tool -P OUTPUT ACCEPT`; unless($? == 0) { print "ERROR: $rc\n"; exit -1 }; $rc = `$tool -F`; unless($? == 0) { print "ERROR: $rc\n"; exit -1 }; $rc = `$tool -L`; unless($? == 0) { print "ERROR: $rc\n"; exit -1 }; foreach $line (split("\n",$rc)) { unless ($line =~ m/Chain\s(.*?)\s\(.*references\)/) { next; } $rc = `$tool -X $1`; unless($? == 0) { print "ERROR: $rc\n"; exit -1 }; } } # ============================== unless (-x $tool) { print "ERROR: $tool isn't executable\n"; exit -1; }; &clear_arptables(); $line = 0; while(<>) { $line++; if(m/^#/) { next; }; if(m/^$/) { next; }; if(m/^\*(.*)/) { $table = $1; next; } # Process a chain directive if(m/^\:(.*?)\s(.*)/) { # is it a user or a built in chain ? if ("$2" eq "-") { $rc = `$tool -t $table -N $1`; unless($? == 0) {print "ERROR(line $line): $rc\n"; exit -1}; next; } $rc = `$tool -t $table -P $1 $2`; unless($? == 0) {print "ERROR(line $line): $rc\n"; exit -1}; next; } $rc = `$tool -t $table $_`; unless($? == 0) {print "ERROR(line $line): $rc\n"; exit -1}; } arptables-0.0.5/arptables-legacy.80000644000175000017500000002743213571215622015771 0ustar pablopablo.TH ARPTABLES 8 "June 2018" .\" .\" Man page originally written by Jochen Friedrich , .\" maintained by Bart De Schuymer. .\" It is based on the iptables man page. .\" .\" Iptables page by Herve Eychenne March 2000. .\" .\" This program is free software; you can redistribute it and/or modify .\" it under the terms of the GNU General Public License as published by .\" the Free Software Foundation; either version 2 of the License, or .\" (at your option) any later version. .\" .\" This program is distributed in the hope that it will be useful, .\" but WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the .\" GNU General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" along with this program; if not, write to the Free Software .\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. .\" .\" .SH NAME arptables \- ARP table administration (legacy) .SH SYNOPSIS .BR "arptables " [ "-t table" ] " -" [ AD ] " chain rule-specification " [ options ] .br .BR "arptables " [ "-t table" ] " -" [ RI ] " chain rulenum rule-specification " [ options ] .br .BR "arptables " [ "-t table" ] " -D chain rulenum " [ options ] .br .BR "arptables " [ "-t table" ] " -" [ "LFZ" ] " " [ chain ] " " [ options ] .br .BR "arptables " [ "-t table" ] " -" [ "NX" ] " chain" .br .BR "arptables " [ "-t table" ] " -E old-chain-name new-chain-name" .br .BR "arptables " [ "-t table" ] " -P chain target " [ options ] .SH LEGACY This tool uses the old xtables/setsockopt framework, and is a legacy version of arptables. That means that a new, more modern tool exists with the same functionality using the nf_tables framework and you are encouraged to migrate now. The new binaries (formerly known as -compat) uses the same syntax and semantics than this legacy one. You can still use this legacy tool. You should probably get some specific information from your Linux distribution or vendor. More docs are available at https://wiki.nftables.org .SH DESCRIPTION .B arptables is a user space tool, it is used to set up and maintain the tables of ARP rules in the Linux kernel. These rules inspect the ARP frames which they see. .B arptables is analogous to the .B iptables user space tool, but .B arptables is less complicated. .SS CHAINS The kernel table is used to divide functionality into different sets of rules. Each set of rules is called a chain. Each chain is an ordered list of rules that can match ARP frames. If a rule matches an ARP frame, then a processing specification tells what to do with that matching frame. The processing specification is called a 'target'. However, if the frame does not match the current rule in the chain, then the next rule in the chain is examined and so forth. The user can create new (user-defined) chains which can be used as the 'target' of a rule. .SS TARGETS A firewall rule specifies criteria for an ARP frame and a frame processing specification called a target. When a frame matches a rule, then the next action performed by the kernel is specified by the target. The target can be one of these values: .IR ACCEPT , .IR DROP , .IR CONTINUE , .IR RETURN , an 'extension' (see below) or a user-defined chain. .PP .I ACCEPT means to let the frame through. .I DROP means the frame has to be dropped. .I CONTINUE means the next rule has to be checked. This can be handy to know how many frames pass a certain point in the chain or to log those frames. .I RETURN means stop traversing this chain and resume at the next rule in the previous (calling) chain. For the extension targets please see the .B "TARGET EXTENSIONS" section of this man page. .SS TABLES There is only one ARP table in the Linux kernel. The table is .BR filter. You can drop the '-t filter' argument to the arptables command. The -t argument must be the first argument on the arptables command line, if used. .TP .B "-t, --table" .br .BR filter , is the only table and contains two (Linux kernels 2.4.X) or three (Linux kernels 2.6.0 and later) built-in chains: .B INPUT (for frames destined for the host), .B OUTPUT (for locally-generated frames) and .B FORWARD (for frames being forwarded by the bridge code). The .B FORWARD chain doesn't exist in Linux 2.4.X kernels. .br .br .SH ARPTABLES COMMAND LINE ARGUMENTS After the initial arptables command line argument, the remaining arguments can be divided into several different groups. These groups are commands, miscellaneous commands, rule-specifications, match-extensions, and watcher-extensions. .SS COMMANDS The arptables command arguments specify the actions to perform on the table defined with the -t argument. If you do not use the -t argument to name a table, the commands apply to the default filter table. With the exception of the .B "-Z" command, only one command may be used on the command line at a time. .TP .B "-A, --append" Append a rule to the end of the selected chain. .TP .B "-D, --delete" Delete the specified rule from the selected chain. There are two ways to use this command. The first is by specifying an interval of rule numbers to delete, syntax: start_nr[:end_nr]. Using negative numbers is allowed, for more details about using negative numbers, see the -I command. The second usage is by specifying the complete rule as it would have been specified when it was added. .TP .B "-I, --insert" Insert the specified rule into the selected chain at the specified rule number. If the current number of rules equals N, then the specified number can be between -N and N+1. For a positive number i, it holds that i and i-N-1 specify the same place in the chain where the rule should be inserted. The number 0 specifies the place past the last rule in the chain and using this number is therefore equivalent with using the -A command. .TP .B "-R, --replace" Replaces the specified rule into the selected chain at the specified rule number. If the current number of rules equals N, then the specified number can be between 1 and N. i specifies the place in the chain where the rule should be replaced. .TP .B "-P, --policy" Set the policy for the chain to the given target. The policy can be .BR ACCEPT ", " DROP " or " RETURN . .TP .B "-F, --flush" Flush the selected chain. If no chain is selected, then every chain will be flushed. Flushing the chain does not change the policy of the chain, however. .TP .B "-Z, --zero" Set the counters of the selected chain to zero. If no chain is selected, all the counters are set to zero. The .B "-Z" command can be used in conjunction with the .B "-L" command. When both the .B "-Z" and .B "-L" commands are used together in this way, the rule counters are printed on the screen before they are set to zero. .TP .B "-L, --list" List all rules in the selected chain. If no chain is selected, all chains are listed. .TP .B "-N, --new-chain" Create a new user-defined chain with the given name. The number of user-defined chains is unlimited. A user-defined chain name has maximum length of 31 characters. .TP .B "-X, --delete-chain" Delete the specified user-defined chain. There must be no remaining references to the specified chain, otherwise .B arptables will refuse to delete it. If no chain is specified, all user-defined chains that aren't referenced will be removed. .TP .B "-E, --rename-chain" Rename the specified chain to a new name. Besides renaming a user-defined chain, you may rename a standard chain name to a name that suits your taste. For example, if you like PREBRIDGING more than PREROUTING, then you can use the -E command to rename the PREROUTING chain. If you do rename one of the standard .B arptables chain names, please be sure to mention this fact should you post a question on the .B arptables mailing lists. It would be wise to use the standard name in your post. Renaming a standard .B arptables chain in this fashion has no effect on the structure or function of the .B arptables kernel table. .SS MISCELLANOUS COMMANDS .TP .B "-V, --version" Show the version of the arptables userspace program. .TP .B "-h, --help" Give a brief description of the command syntax. .TP .BR "-j, --jump " "\fItarget\fP" The target of the rule. This is one of the following values: .BR ACCEPT , .BR DROP , .BR CONTINUE , .BR RETURN , a target extension (see .BR "TARGET EXTENSIONS" ")" or a user-defined chain name. .TP .BI "-c, --set-counters " "PKTS BYTES" This enables the administrator to initialize the packet and byte counters of a rule (during .B INSERT, .B APPEND, .B REPLACE operations). .SS RULE-SPECIFICATIONS The following command line arguments make up a rule specification (as used in the add and delete commands). A "!" option before the specification inverts the test for that specification. Apart from these standard rule specifications there are some other command line arguments of interest. .TP .BR "-s, --source-ip " "[!] \fIaddress\fP[/\fImask]\fP" The Source IP specification. .TP .BR "-d, --destination-ip " "[!] \fIaddress\fP[/\fImask]\fP" The Destination IP specification. .TP .BR "--source-mac " "[!] \fIaddress\fP[/\fImask\fP]" The source mac address. Both mask and address are written as 6 hexadecimal numbers separated by colons. .TP .BR "--destination-mac " "[!] \fIaddress\fP[/\fImask\fP]" The destination mac address. Both mask and address are written as 6 hexadecimal numbers separated by colons. .TP .BR "-i, --in-interface " "[!] \fIname\fP" The interface via which a frame is received (for the .BR INPUT " and " FORWARD chains). The flag .B --in-if is an alias for this option. .TP .BR "-o, --out-interface " "[!] \fIname\fP" The interface via which a frame is going to be sent (for the .BR OUTPUT " and " FORWARD chains). The flag .B --out-if is an alias for this option. .TP .BR "-l, --h-length " "\fIlength\fP[/\fImask\fP]" The hardware length (nr of bytes) .TP .BR "--opcode " "\fIcode\fP[/\fImask\fP] The operation code (2 bytes). Available values are: .BR 1 = Request .BR 2 = Reply .BR 3 = Request_Reverse .BR 4 = Reply_Reverse .BR 5 = DRARP_Request .BR 6 = DRARP_Reply .BR 7 = DRARP_Error .BR 8 = InARP_Request .BR 9 = ARP_NAK . .TP .BR "--h-type " "\fItype\fP[/\fImask\fP]" The hardware type (2 bytes, hexadecimal). Available values are: .BR 1 = Ethernet . .TP .BR "--proto-type " "\fItype\fP[/\fImask\fP]" The protocol type (2 bytes). Available values are: .BR 0x800 = IPv4 . .SS TARGET-EXTENSIONS .B arptables extensions are precompiled into the userspace tool. So there is no need to explicitly load them with a -m option like in .BR iptables . However, these extensions deal with functionality supported by supplemental kernel modules. .SS mangle .TP .BR "--mangle-ip-s IP address" Mangles Source IP Address to given value. .TP .BR "--mangle-ip-d IP address" Mangles Destination IP Address to given value. .TP .BR "--mangle-mac-s MAC address" Mangles Source MAC Address to given value. .TP .BR "--mangle-mac-d MAC address" Mangles Destination MAC Address to given value. .TP .BR "--mangle-target target " Target of ARP mangle operation .BR "" ( DROP ", " CONTINUE " or " ACCEPT " -- default is " ACCEPT ). .SS CLASSIFY This module allows you to set the skb->priority value (and thus clas- sify the packet into a specific CBQ class). .TP .BR "--set-class major:minor" Set the major and minor class value. The values are always interpreted as hexadecimal even if no 0x prefix is given. .SS MARK This module allows you to set the skb->mark value (and thus classify the packet by the mark in u32) .TP .BR "--set-mark mark" Set the mark value. The values are always interpreted as hexadecimal even if no 0x prefix is given .TP .BR "--and-mark mark" Binary AND the mark with bits. .TP .BR "--or-mark mark" Binary OR the mark with bits. .SH MAILINGLISTS .BR "" "See " http://netfilter.org/mailinglists.html .SH SEE ALSO .BR iptables "(8), " ebtables "(8), " arp "(8), " rarp "(8), " ifconfig "(8), " route (8) .PP .BR "" "See " http://ebtables.sf.net arptables-0.0.5/Makefile0000644000175000017500000000431513571215622014114 0ustar pablopabloARPTABLES_VERSION:=0.0.5 KERNEL_DIR:=./ # default paths PREFIX:=/usr/local LIBDIR:=$(PREFIX)/lib BINDIR:=$(PREFIX)/sbin MANDIR:=$(PREFIX)/man man8dir=$(MANDIR)/man8 SYSCONFIGDIR:=/etc/sysconfig DESTDIR:= MANS = arptables-legacy.8 arptables-save.8 arptables-restore.8 COPT_FLAGS:=-O2 CFLAGS:=$(COPT_FLAGS) -Wall -Wunused -I$(KERNEL_DIR)/include/ -Iinclude/ -DARPTABLES_VERSION=\"$(ARPTABLES_VERSION)\" #-g -DDEBUG #-pg # -DARPTC_DEBUG ifndef ARPT_LIBDIR ARPT_LIBDIR:=$(LIBDIR)/arptables endif include extensions/Makefile all: arptables-legacy libarptc/libarptc.a arptables.o: arptables.c $(CC) $(CFLAGS) -c -o $@ $< arptables-standalone.o: arptables-standalone.c $(CC) $(CFLAGS) -c -o $@ $< libarptc/libarptc.o: libarptc/libarptc.c libarptc/libarptc_incl.c $(CC) $(CFLAGS) -c -o $@ $< libarptc/libarptc.a: libarptc/libarptc.o $(AR) rcs $@ $< arptables-legacy: arptables-standalone.o arptables.o libarptc/libarptc.o $(EXT_OBJS) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(DESTDIR)$(BINDIR)/arptables-legacy: arptables-legacy mkdir -p $(DESTDIR)$(BINDIR) install -m 0755 $< $@ tmp1:=$(shell printf $(BINDIR) | sed 's/\//\\\//g') tmp2:=$(shell printf $(SYSCONFIGDIR) | sed 's/\//\\\//g') .PHONY: scripts scripts: arptables-save arptables-restore cat arptables-save | sed 's/__EXEC_PATH__/$(tmp1)/g' > arptables-save_ install -m 0755 arptables-save_ $(DESTDIR)$(BINDIR)/arptables-save cat arptables-restore | sed 's/__EXEC_PATH__/$(tmp1)/g' > arptables-restore_ install -m 0755 arptables-restore_ $(DESTDIR)$(BINDIR)/arptables-restore rm -f arptables-save_ arptables-restore_ .PHONY: install-man install-man: $(MANS) [ -d "$(DESTDIR)$(man8dir)" ] || mkdir -p "$(DESTDIR)$(man8dir)" install -m 0644 $^ $(DESTDIR)$(man8dir)/ .PHONY: install install: install-man $(DESTDIR)$(BINDIR)/arptables-legacy scripts .PHONY: clean clean: rm -f arptables-legacy rm -f *.o *~ rm -f extensions/*.o extensions/*~ rm -f libarptc/*.o libarptc/*~ libarptc/*.a rm -f include/*~ include/libarptc/*~ DIR:=arptables-v$(ARPTABLES_VERSION) # This is used to make a new userspace release .PHONY: release release: make clean cd ..;find $(DIR) -exec touch {} \;;find $(DIR) -exec chmod o-r,g-r,o-w,g-w,o-x,g-x {} \;;tar -pc $(DIR) | gzip >$(DIR).tar.gz arptables-0.0.5/COPYING0000644000175000017500000004327613571215622013520 0ustar pablopabloAll code in this package, including the code from the extensions, is released under the GPL license, which you find hereafter. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. arptables-0.0.5/.gitignore0000644000175000017500000000004013571215622014433 0ustar pablopablo*.a *.o /arptables-legacy /tags