libiptc.c revision 228e98dd6303af11925235af4cf3c3ec450f3f41
1e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Library which manipulates firewall rules. Version 0.1. */ 2e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 3e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Architecture of firewall rules is as follows: 4e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * 5e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Chains go INPUT, FORWARD, OUTPUT then user chains. 6e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Each user chain starts with an ERROR node. 7e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Every chain ends with an unconditional jump: a RETURN for user chains, 8e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * and a POLICY for built-ins. 9e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher */ 10e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 11e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* (C)1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See 12e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher COPYING for details). */ 13e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 14e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <assert.h> 15e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <string.h> 16e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <errno.h> 17e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdlib.h> 18e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdio.h> 19edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell#include <limits.h> 20e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 21e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if !defined(__GLIBC__) || (__GLIBC__ < 2) 22e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchertypedef unsigned int socklen_t; 23e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif 24e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 25e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <libiptc/libiptc.h> 26edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell#include <linux/netfilter_ipv4/ipt_limit.h> 27e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 28e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IP_VERSION 4 29e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IP_OFFSET 0x1FFF 30e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 31e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#ifndef IPT_LIB_DIR 32e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IPT_LIB_DIR "/usr/local/lib/iptables" 33e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif 34e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 3530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#if 0 3630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstatic struct ipt_entry_target * 3730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellipt_get_target(struct ipt_entry *e) 3830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{ 3930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell return (void *)e + e->target_offset; 4030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell} 4130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#endif 4230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 43e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int sockfd = -1; 44e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void *iptc_fn = NULL; 45e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 46e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const char *hooknames[] 47e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher= { [NF_IP_PRE_ROUTING] "PREROUTING", 48e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher [NF_IP_LOCAL_IN] "INPUT", 49e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher [NF_IP_FORWARD] "FORWARD", 50e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher [NF_IP_LOCAL_OUT] "OUTPUT", 51e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher [NF_IP_POST_ROUTING] "POSTROUTING" 52e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}; 53e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 54e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct counter_map 55e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 56e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher enum { 57e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher COUNTER_MAP_NOMAP, 58e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher COUNTER_MAP_NORMAL_MAP, 59e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher COUNTER_MAP_ZEROED 60e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } maptype; 61e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int mappos; 62e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}; 63e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 64e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Convenience structures */ 65e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct ipt_error_target 66e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 67e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry_target t; 68e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher char error[IPT_TABLE_MAXNAMELEN]; 69e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}; 70e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 7130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstruct chain_cache 7230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{ 7330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell char name[IPT_TABLE_MAXNAMELEN]; 7430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell /* This is the first rule in chain. */ 7530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell struct ipt_entry *start; 7630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell /* Last rule in chain */ 7730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell struct ipt_entry *end; 7830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell}; 7930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 80e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct iptc_handle 81e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 82e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Have changes been made? */ 83e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int changed; 84e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Size in here reflects original state. */ 85e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_getinfo info; 86e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 87e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct counter_map *counter_map; 88e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Array of hook names */ 89e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher const char **hooknames; 90e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 9130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell /* Cached position of chain heads (NULL = no cache). */ 9230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell unsigned int cache_num_chains; 9330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell unsigned int cache_num_builtins; 9430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell struct chain_cache *cache_chain_heads; 9530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 9630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell /* Chain iterator: current chain cache entry. */ 9730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell struct chain_cache *cache_chain_iteration; 9830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 9930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell /* Rule iterator: terminal rule */ 10030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell struct ipt_entry *cache_rule_end; 101175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell 102e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Number in here reflects current state. */ 103e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int new_number; 104e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_get_entries entries; 105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}; 106e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 107175f64177743e5a417e98d483ef995bf7151f3bcRusty Russellstatic void 108175f64177743e5a417e98d483ef995bf7151f3bcRusty Russellset_changed(iptc_handle_t h) 109175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell{ 11030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (h->cache_chain_heads) { 11130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell free(h->cache_chain_heads); 11230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell h->cache_chain_heads = NULL; 11330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell h->cache_num_chains = 0; 11430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell h->cache_chain_iteration = NULL; 11530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell h->cache_rule_end = NULL; 11630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell } 117175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell h->changed = 1; 118175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell} 119175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell 12030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#ifndef NDEBUG 121e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void do_check(iptc_handle_t h, unsigned int line); 122849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell#define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0) 12330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#else 12430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#define CHECK(h) 12530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#endif 126e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 127e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int 128e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherget_number(const struct ipt_entry *i, 129e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher const struct ipt_entry *seek, 130e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int *pos) 131e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 132e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (i == seek) 133e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 1; 134e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*pos)++; 135e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 136e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 137e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 138e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic unsigned int 139e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherentry2index(const iptc_handle_t h, const struct ipt_entry *seek) 140e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 141e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int pos = 0; 142e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 143e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (IPT_ENTRY_ITERATE(h->entries.entries, h->entries.size, 144e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher get_number, seek, &pos) == 0) { 145e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher fprintf(stderr, "ERROR: offset %i not an entry!\n", 146e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (unsigned char *)seek - h->entries.entries); 147e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher abort(); 148e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 149e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return pos; 150e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 151e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 152e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int 153e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherget_entry_n(struct ipt_entry *i, 154e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int number, 155e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int *pos, 156e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry **pe) 157e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 158e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (*pos == number) { 159e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *pe = i; 160e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 1; 161e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 162e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*pos)++; 163e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 164e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 165e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 166e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic struct ipt_entry * 167e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherindex2entry(iptc_handle_t h, unsigned int index) 168e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 169e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int pos = 0; 170e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry *ret = NULL; 171e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 172e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher IPT_ENTRY_ITERATE(h->entries.entries, h->entries.size, 173e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher get_entry_n, index, &pos, &ret); 174e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 175e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return ret; 176e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 177e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 178e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline struct ipt_entry * 179e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherget_entry(iptc_handle_t h, unsigned int offset) 180e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 181e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return (struct ipt_entry *)(h->entries.entries + offset); 182e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 183e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 184e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline unsigned long 185e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherentry2offset(const iptc_handle_t h, const struct ipt_entry *e) 186e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 187e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return (unsigned char *)e - h->entries.entries; 188e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 189e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 190e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic unsigned long 191e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherindex2offset(iptc_handle_t h, unsigned int index) 192e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 193e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return entry2offset(h, index2entry(h, index)); 194e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 195e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 196e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic const char * 197e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherget_errorlabel(iptc_handle_t h, unsigned int offset) 198e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 199e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry *e; 200e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 201e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher e = get_entry(h, offset); 202228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell if (strcmp(ipt_get_target(e)->u.user.name, IPT_ERROR_TARGET) != 0) { 203e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher fprintf(stderr, "ERROR: offset %u not an error node!\n", 204e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher offset); 205e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher abort(); 206e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 207e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 208e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return (const char *)ipt_get_target(e)->data; 209e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 210e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 211e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Allocate handle of given size */ 212e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic iptc_handle_t 213e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheralloc_handle(const char *tablename, unsigned int size, unsigned int num_rules) 214e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 215e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher size_t len; 216e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_handle_t h; 217e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 218e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher len = sizeof(struct iptc_handle) 219e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher + size 220e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher + num_rules * sizeof(struct counter_map); 221e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 222e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if ((h = malloc(len)) == NULL) { 223e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOMEM; 224e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return NULL; 225e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 226e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 227e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher h->changed = 0; 22830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell h->cache_num_chains = 0; 22930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell h->cache_chain_heads = NULL; 230e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher h->counter_map = (void *)h 231e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher + sizeof(struct iptc_handle) 232e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher + size; 233e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher strcpy(h->info.name, tablename); 234e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher strcpy(h->entries.name, tablename); 235e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 236e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return h; 237e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 238e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 239e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_handle_t 240e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_init(const char *tablename) 241e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 242e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_handle_t h; 243e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_getinfo info; 244e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int i; 245e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int tmp; 246e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher socklen_t s; 247e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 248e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_fn = iptc_init; 249e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 250e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 251e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (sockfd < 0) 252e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return NULL; 253e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 254e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher s = sizeof(info); 255e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (strlen(tablename) >= IPT_TABLE_MAXNAMELEN) { 256e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = EINVAL; 257e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return NULL; 258e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 259e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher strcpy(info.name, tablename); 260e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (getsockopt(sockfd, IPPROTO_IP, IPT_SO_GET_INFO, &info, &s) < 0) 261e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return NULL; 262e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 263e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if ((h = alloc_handle(info.name, info.size, info.num_entries)) 264e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher == NULL) 265e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return NULL; 266e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 267e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Too hard --RR */ 268e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if 0 269e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher sprintf(pathname, "%s/%s", IPT_LIB_DIR, info.name); 270e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher dynlib = dlopen(pathname, RTLD_NOW); 271e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!dynlib) { 272e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOENT; 273e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return NULL; 274e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 275e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher h->hooknames = dlsym(dynlib, "hooknames"); 276e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!h->hooknames) { 277e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOENT; 278e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return NULL; 279e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 280e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#else 281e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher h->hooknames = hooknames; 282e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif 283e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 284e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Initialize current state */ 285e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher h->info = info; 286e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher h->new_number = h->info.num_entries; 287e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher for (i = 0; i < h->info.num_entries; i++) 288e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher h->counter_map[i] 289e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher = ((struct counter_map){COUNTER_MAP_NORMAL_MAP, i}); 290e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 291e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher h->entries.size = h->info.size; 292e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 293e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher tmp = sizeof(struct ipt_get_entries) + h->info.size; 294e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 295e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (getsockopt(sockfd, IPPROTO_IP, IPT_SO_GET_ENTRIES, &h->entries, 296e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher &tmp) < 0) { 297e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher free(h); 298e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return NULL; 299e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 3007e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell 301e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher CHECK(h); 302e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return h; 303e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 304e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 305e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IP_PARTS_NATIVE(n) \ 306e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)>>24)&0xFF, \ 307e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)>>16)&0xFF, \ 308e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)>>8)&0xFF, \ 309e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher(unsigned int)((n)&0xFF) 310e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 311e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n)) 312e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 313e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int 314e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherprint_match(const struct ipt_entry_match *m) 315e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 316228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell printf("Match name: `%s'\n", m->u.user.name); 317e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 318e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 319e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 320e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint 321e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherdump_entry(struct ipt_entry *e, const iptc_handle_t handle) 322e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 323e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher size_t i; 324e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry_target *t; 325e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 326e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("Entry %u (%lu):\n", entry2index(handle, e), 327e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher entry2offset(handle, e)); 328e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("SRC IP: %u.%u.%u.%u/%u.%u.%u.%u\n", 329e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher IP_PARTS(e->ip.src.s_addr),IP_PARTS(e->ip.smsk.s_addr)); 330e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("DST IP: %u.%u.%u.%u/%u.%u.%u.%u\n", 331e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher IP_PARTS(e->ip.dst.s_addr),IP_PARTS(e->ip.dmsk.s_addr)); 332e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("Interface: `%s'/", e->ip.iniface); 333e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher for (i = 0; i < IFNAMSIZ; i++) 334e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("%c", e->ip.iniface_mask[i] ? 'X' : '.'); 335e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("to `%s'/", e->ip.outiface); 336e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher for (i = 0; i < IFNAMSIZ; i++) 337e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("%c", e->ip.outiface_mask[i] ? 'X' : '.'); 338e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("\nProtocol: %u\n", e->ip.proto); 339e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("Flags: %02X\n", e->ip.flags); 340e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("Invflags: %02X\n", e->ip.invflags); 341e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("Counters: %llu packets, %llu bytes\n", 342e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher e->counters.pcnt, e->counters.bcnt); 343e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("Cache: %08X ", e->nfcache); 344e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (e->nfcache & NFC_ALTERED) printf("ALTERED "); 345e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (e->nfcache & NFC_UNKNOWN) printf("UNKNOWN "); 346e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (e->nfcache & NFC_IP_SRC) printf("IP_SRC "); 347e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (e->nfcache & NFC_IP_DST) printf("IP_DST "); 348e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (e->nfcache & NFC_IP_IF_IN) printf("IP_IF_IN "); 349e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (e->nfcache & NFC_IP_IF_OUT) printf("IP_IF_OUT "); 350e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (e->nfcache & NFC_IP_TOS) printf("IP_TOS "); 351e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (e->nfcache & NFC_IP_PROTO) printf("IP_PROTO "); 352e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (e->nfcache & NFC_IP_OPTIONS) printf("IP_OPTIONS "); 353e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (e->nfcache & NFC_IP_TCPFLAGS) printf("IP_TCPFLAGS "); 354e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (e->nfcache & NFC_IP_SRC_PT) printf("IP_SRC_PT "); 355e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (e->nfcache & NFC_IP_DST_PT) printf("IP_DST_PT "); 356e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (e->nfcache & NFC_IP_PROTO_UNKNOWN) printf("IP_PROTO_UNKNOWN "); 357e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("\n"); 358e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 359e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher IPT_MATCH_ITERATE(e, print_match); 360e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 361e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher t = ipt_get_target(e); 362228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell printf("Target name: `%s' [%u]\n", t->u.user.name, t->u.target_size); 363228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell if (strcmp(t->u.user.name, IPT_STANDARD_TARGET) == 0) { 364e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int pos = *(int *)t->data; 365e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (pos < 0) 366e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("verdict=%s\n", 367e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher pos == -NF_ACCEPT-1 ? "NF_ACCEPT" 368e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher : pos == -NF_DROP-1 ? "NF_DROP" 369e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher : pos == -NF_QUEUE-1 ? "NF_QUEUE" 370e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher : pos == IPT_RETURN ? "RETURN" 371e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher : "UNKNOWN"); 372e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher else 373e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("verdict=%u\n", pos); 374228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell } else if (strcmp(t->u.user.name, IPT_ERROR_TARGET) == 0) 375e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("error=`%s'\n", t->data); 376e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 377e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("\n"); 378e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 379e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 380e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 381e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid 382e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherdump_entries(const iptc_handle_t handle) 383e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 384e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher CHECK(handle); 385e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 386e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("libiptc v%s. %u entries, %u bytes.\n", 387e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher NETFILTER_VERSION, 388e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher handle->new_number, handle->entries.size); 389e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("Table `%s'\n", handle->info.name); 390e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n", 391e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher handle->info.hook_entry[NF_IP_PRE_ROUTING], 392e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher handle->info.hook_entry[NF_IP_LOCAL_IN], 393e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher handle->info.hook_entry[NF_IP_FORWARD], 394e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher handle->info.hook_entry[NF_IP_LOCAL_OUT], 395e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher handle->info.hook_entry[NF_IP_POST_ROUTING]); 396e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("Underflows: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n", 397e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher handle->info.underflow[NF_IP_PRE_ROUTING], 398e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher handle->info.underflow[NF_IP_LOCAL_IN], 399e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher handle->info.underflow[NF_IP_FORWARD], 400e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher handle->info.underflow[NF_IP_LOCAL_OUT], 401e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher handle->info.underflow[NF_IP_POST_ROUTING]); 402e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 403e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher IPT_ENTRY_ITERATE(handle->entries.entries, handle->entries.size, 404e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher dump_entry, handle); 405e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 406e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 40730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Returns 0 if not hook entry, else hooknumber + 1 */ 40830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstatic inline unsigned int 40930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellis_hook_entry(struct ipt_entry *e, iptc_handle_t h) 41030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{ 41130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell unsigned int i; 41230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 41330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell for (i = 0; i < NF_IP_NUMHOOKS; i++) { 41430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if ((h->info.valid_hooks & (1 << i)) 41530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell && get_entry(h, h->info.hook_entry[i]) == e) 41630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell return i+1; 41730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell } 41830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell return 0; 41930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell} 42030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 421e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int 42230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russelladd_chain(struct ipt_entry *e, iptc_handle_t h, struct ipt_entry **prev) 423e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 42430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell unsigned int builtin; 425e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 42630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell /* Last entry. End it. */ 42730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (entry2offset(h, e) + e->next_offset == h->entries.size) { 42830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell /* This is the ERROR node at end of the table */ 42930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell h->cache_chain_heads[h->cache_num_chains-1].end = *prev; 43030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell return 0; 43130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell } 432e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 43330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell /* We know this is the start of a new chain if it's an ERROR 43430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell target, or a hook entry point */ 435228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell if (strcmp(ipt_get_target(e)->u.user.name, IPT_ERROR_TARGET) == 0) { 43630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell /* prev was last entry in previous chain */ 43730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell h->cache_chain_heads[h->cache_num_chains-1].end 43830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell = *prev; 43930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 44030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell strcpy(h->cache_chain_heads[h->cache_num_chains].name, 44130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell (const char *)ipt_get_target(e)->data); 44230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell h->cache_chain_heads[h->cache_num_chains].start 44330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell = (void *)e + e->next_offset; 44430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell h->cache_num_chains++; 44530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell } else if ((builtin = is_hook_entry(e, h)) != 0) { 44630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (h->cache_num_chains > 0) 44730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell /* prev was last entry in previous chain */ 44830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell h->cache_chain_heads[h->cache_num_chains-1].end 44930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell = *prev; 45030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 45130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell strcpy(h->cache_chain_heads[h->cache_num_chains].name, 45230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell h->hooknames[builtin-1]); 45330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell h->cache_chain_heads[h->cache_num_chains].start 45430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell = (void *)e; 45530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell h->cache_num_chains++; 45630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell } 45730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 45830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell *prev = e; 459e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 460e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 461e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 46230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstatic int alphasort(const void *a, const void *b) 46330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{ 46430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell return strcmp(((struct chain_cache *)a)->name, 46530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell ((struct chain_cache *)b)->name); 46630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell} 46730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 46830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstatic int populate_cache(iptc_handle_t h) 469e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 470e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int i; 47130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell struct ipt_entry *prev; 472e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 47330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell /* # chains < # rules / 2 + num builtins - 1 */ 47430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell h->cache_chain_heads = malloc((h->new_number / 2 + 4) 47530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell * sizeof(struct chain_cache)); 47630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (!h->cache_chain_heads) { 47730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell errno = ENOMEM; 47830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell return 0; 479175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell } 480175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell 48130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell h->cache_num_chains = 0; 48230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell h->cache_num_builtins = 0; 48330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 48430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell /* Count builtins */ 48530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell for (i = 0; i < NF_IP_NUMHOOKS; i++) { 48630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (h->info.valid_hooks & (1 << i)) 48730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell h->cache_num_builtins++; 488e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 489e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 49030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell prev = NULL; 49130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell IPT_ENTRY_ITERATE(h->entries.entries, h->entries.size, 49230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell add_chain, h, &prev); 49330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 49430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell qsort(h->cache_chain_heads + h->cache_num_builtins, 49530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell h->cache_num_chains - h->cache_num_builtins, 49630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell sizeof(struct chain_cache), alphasort); 49730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 49830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell return 1; 49930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell} 50030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 50130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Returns cache ptr if found, otherwise NULL. */ 50230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstatic struct chain_cache * 50330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellfind_label(const char *name, iptc_handle_t handle) 50430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{ 505849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell unsigned int i; 50630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 50730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (handle->cache_chain_heads == NULL 50830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell && !populate_cache(handle)) 50930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell return NULL; 51030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 511849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell /* FIXME: Linear search through builtins, then binary --RR */ 512849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell for (i = 0; i < handle->cache_num_chains; i++) { 513849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell if (strcmp(handle->cache_chain_heads[i].name, name) == 0) 514849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell return &handle->cache_chain_heads[i]; 515e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 516e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 517849779c4adf8dd65c83fffb65e6b7898df2a55c6Rusty Russell return NULL; 518e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 519e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 520e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Does this chain exist? */ 521e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint iptc_is_chain(const char *chain, const iptc_handle_t handle) 522e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 52330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell return find_label(chain, handle) != NULL; 524e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 525e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 526e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Returns the position of the final (ie. unconditional) element. */ 527e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic unsigned int 528e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherget_chain_end(const iptc_handle_t handle, unsigned int start) 529e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 530e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int last_off, off; 531e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry *e; 532e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 533e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher last_off = start; 534e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher e = get_entry(handle, start); 535e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 536e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Terminate when we meet a error label or a hook entry. */ 537e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher for (off = start + e->next_offset; 538e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher off < handle->entries.size; 539e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher last_off = off, off += e->next_offset) { 540e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry_target *t; 541e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int i; 542e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 543e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher e = get_entry(handle, off); 544e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 545e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* We hit an entry point. */ 546e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher for (i = 0; i < NF_IP_NUMHOOKS; i++) { 547e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if ((handle->info.valid_hooks & (1 << i)) 548e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher && off == handle->info.hook_entry[i]) 549e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return last_off; 550e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 551e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 552e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* We hit a user chain label */ 553e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher t = ipt_get_target(e); 554228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell if (strcmp(t->u.user.name, IPT_ERROR_TARGET) == 0) 555e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return last_off; 556e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 557e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* SHOULD NEVER HAPPEN */ 558e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher fprintf(stderr, "ERROR: Off end (%u) of chain from %u!\n", 559e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher handle->entries.size, off); 560e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher abort(); 561e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 562e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 56330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Iterator functions to run through the chains. */ 564e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char * 56530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russelliptc_first_chain(iptc_handle_t *handle) 566e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 56730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if ((*handle)->cache_chain_heads == NULL 56830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell && !populate_cache(*handle)) 569e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return NULL; 570e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 57130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell (*handle)->cache_chain_iteration 57230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell = &(*handle)->cache_chain_heads[0]; 57330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 57430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell return (*handle)->cache_chain_iteration->name; 57530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell} 57630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 57730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Iterator functions to run through the chains. Returns NULL at end. */ 57830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellconst char * 57930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russelliptc_next_chain(iptc_handle_t *handle) 58030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{ 58130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell (*handle)->cache_chain_iteration++; 58230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 58330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if ((*handle)->cache_chain_iteration - (*handle)->cache_chain_heads 58430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell == (*handle)->cache_num_chains) 58530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell return NULL; 58630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 58730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell return (*handle)->cache_chain_iteration->name; 58830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell} 58930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 59030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Get first rule in the given chain: NULL for empty chain. */ 59130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellconst struct ipt_entry * 59230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russelliptc_first_rule(const char *chain, iptc_handle_t *handle) 59330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{ 59430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell struct chain_cache *c; 59530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 59630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell c = find_label(chain, *handle); 59730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (!c) { 59830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell errno = ENOENT; 59930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell return NULL; 600e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 601e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 60230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell /* Empty chain: single return/policy rule */ 60330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (c->start == c->end) 60430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell return NULL; 60530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 60630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell (*handle)->cache_rule_end = c->end; 60730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell return c->start; 608e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 609e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 61030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell/* Returns NULL when rules run out. */ 61130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellconst struct ipt_entry * 61230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russelliptc_next_rule(const struct ipt_entry *prev, iptc_handle_t *handle) 61330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell{ 61430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if ((void *)prev + prev->next_offset 61530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell == (void *)(*handle)->cache_rule_end) 61630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell return NULL; 61730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 61830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell return (void *)prev + prev->next_offset; 61930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell} 62030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 62130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#if 0 622e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* How many rules in this chain? */ 623e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherunsigned int 624e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_num_rules(const char *chain, iptc_handle_t *handle) 625e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 626e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int off = 0; 627e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry *start, *end; 628e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 629e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher CHECK(*handle); 630e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!find_label(&off, chain, *handle)) { 631e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOENT; 632e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return (unsigned int)-1; 633e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 634e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 635e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher start = get_entry(*handle, off); 636e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher end = get_entry(*handle, get_chain_end(*handle, off)); 637e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 638e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return entry2index(*handle, end) - entry2index(*handle, start); 639e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 640e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 641e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get n'th rule in this chain. */ 642e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst struct ipt_entry *iptc_get_rule(const char *chain, 643e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int n, 644e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_handle_t *handle) 645e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 646e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int pos = 0, chainindex; 647e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 648e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher CHECK(*handle); 649e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!find_label(&pos, chain, *handle)) { 650e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOENT; 651e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return NULL; 652e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 653e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 654e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher chainindex = entry2index(*handle, get_entry(*handle, pos)); 655e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 656e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return index2entry(*handle, chainindex + n); 657e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 65830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#endif 659e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 66030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellstatic const char * 66130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russelltarget_name(iptc_handle_t handle, const struct ipt_entry *ce) 662e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 663e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int spos; 664e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int labelidx; 665e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry *jumpto; 666e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 66730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell /* To avoid const warnings */ 66830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell struct ipt_entry *e = (struct ipt_entry *)ce; 66930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell 670228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell if (strcmp(ipt_get_target(e)->u.user.name, IPT_STANDARD_TARGET) != 0) 671228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell return ipt_get_target(e)->u.user.name; 672e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 673e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Standard target: evaluate */ 674e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher spos = *(int *)ipt_get_target(e)->data; 675e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (spos < 0) { 676e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (spos == IPT_RETURN) 677e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return IPTC_LABEL_RETURN; 678e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher else if (spos == -NF_ACCEPT-1) 679e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return IPTC_LABEL_ACCEPT; 680e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher else if (spos == -NF_DROP-1) 681e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return IPTC_LABEL_DROP; 6822f4e5d92c73906e0dc2ae42fee5c05740528e92bJames Morris else if (spos == -NF_QUEUE-1) 683e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return IPTC_LABEL_QUEUE; 684e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 685e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher fprintf(stderr, "ERROR: off %lu/%u not a valid target (%i)\n", 686e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher entry2offset(handle, e), handle->entries.size, 687e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher spos); 688e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher abort(); 689e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 690e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 691e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher jumpto = get_entry(handle, spos); 692e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 693e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Fall through rule */ 694e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (jumpto == (void *)e + e->next_offset) 695e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return ""; 696e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 697e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Must point to head of a chain: ie. after error rule */ 698e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher labelidx = entry2index(handle, jumpto) - 1; 699e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return get_errorlabel(handle, index2offset(handle, labelidx)); 700e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 701e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 702e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Returns a pointer to the target name of this position. */ 70330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russellconst char *iptc_get_target(const struct ipt_entry *e, 704e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_handle_t *handle) 705e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 706e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return target_name(*handle, e); 707e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 708e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 709e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Is this a built-in chain? Actually returns hook + 1. */ 710e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint 711e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_builtin(const char *chain, const iptc_handle_t handle) 712e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 713e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int i; 714e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 715e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher for (i = 0; i < NF_IP_NUMHOOKS; i++) { 716e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if ((handle->info.valid_hooks & (1 << i)) 717e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher && handle->hooknames[i] 718e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher && strcmp(handle->hooknames[i], chain) == 0) 719e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return i+1; 720e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 721e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 722e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 723e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 724e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get the policy of a given built-in chain */ 725e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char * 726e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_get_policy(const char *chain, 727e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_counters *counters, 728e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_handle_t *handle) 729e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 730e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int start; 731e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry *e; 732e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int hook; 733e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 734e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher hook = iptc_builtin(chain, *handle); 735e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (hook != 0) 736e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher start = (*handle)->info.hook_entry[hook-1]; 737e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher else 738e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return NULL; 739e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 740e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher e = get_entry(*handle, get_chain_end(*handle, start)); 741e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *counters = e->counters; 742e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 743e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return target_name(*handle, e); 744e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 745e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 746e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int 747e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchercorrect_verdict(struct ipt_entry *e, 748e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned char *base, 749e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int offset, int delta_offset) 750e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 751e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_standard_target *t = (void *)ipt_get_target(e); 752e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int curr = (unsigned char *)e - base; 753e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 754e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Trap: insert of fall-through rule. Don't change fall-through 755e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher verdict to jump-over-next-rule. */ 756228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell if (strcmp(t->target.u.user.name, IPT_STANDARD_TARGET) == 0 757e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher && t->verdict > (int)offset 758e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher && !(curr == offset && 759e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher t->verdict == curr + e->next_offset)) { 760e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher t->verdict += delta_offset; 761e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 762e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 763e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 764e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 765e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 766e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Adjusts standard verdict jump positions after an insertion/deletion. */ 767e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int 768e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherset_verdict(unsigned int offset, int delta_offset, iptc_handle_t *handle) 769e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 770e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher IPT_ENTRY_ITERATE((*handle)->entries.entries, 771e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*handle)->entries.size, 772e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher correct_verdict, (*handle)->entries.entries, 773e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher offset, delta_offset); 774e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 775175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell set_changed(*handle); 776e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 1; 777e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 778e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 779e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* If prepend is set, then we are prepending to a chain: if the 780e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * insertion position is an entry point, keep the entry point. */ 781e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int 782e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherinsert_rules(unsigned int num_rules, unsigned int rules_size, 783e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher const struct ipt_entry *insert, 784e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int offset, unsigned int num_rules_offset, 785e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int prepend, 786e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_handle_t *handle) 787e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 788e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_handle_t newh; 789e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_getinfo newinfo; 790e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int i; 791e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 792e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (offset >= (*handle)->entries.size) { 793e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = EINVAL; 794e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 795e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 796e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 797e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher newinfo = (*handle)->info; 798e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 799e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Fix up entry points. */ 800e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher for (i = 0; i < NF_IP_NUMHOOKS; i++) { 801e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Entry points to START of chain, so keep same if 802e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher inserting on at that point. */ 803e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if ((*handle)->info.hook_entry[i] > offset) 804e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher newinfo.hook_entry[i] += rules_size; 805e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 806e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Underflow always points to END of chain (policy), 807e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher so if something is inserted at same point, it 808e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher should be advanced. */ 809e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if ((*handle)->info.underflow[i] >= offset) 810e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher newinfo.underflow[i] += rules_size; 811e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 812e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 813e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher newh = alloc_handle((*handle)->info.name, 814e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*handle)->info.size + rules_size, 815e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*handle)->info.num_entries + num_rules); 816e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!newh) 817e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 818e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher newh->info = newinfo; 819e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 820e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Copy pre... */ 821e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher memcpy(newh->entries.entries, (*handle)->entries.entries, offset); 822e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* ... Insert new ... */ 823e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher memcpy(newh->entries.entries + offset, insert, rules_size); 824e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* ... copy post */ 825e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher memcpy(newh->entries.entries + offset + rules_size, 826e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*handle)->entries.entries + offset, 827e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*handle)->entries.size - offset); 828e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 829e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Move counter map. */ 830e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Copy pre... */ 831e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher memcpy(newh->counter_map, (*handle)->counter_map, 832e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher sizeof(struct counter_map) * num_rules_offset); 833e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* ... copy post */ 834e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher memcpy(newh->counter_map + num_rules_offset + num_rules, 835e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*handle)->counter_map + num_rules_offset, 836e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher sizeof(struct counter_map) * ((*handle)->new_number 837e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher - num_rules_offset)); 838e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Set intermediates to no counter copy */ 839e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher for (i = 0; i < num_rules; i++) 840e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher newh->counter_map[num_rules_offset+i] 841e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher = ((struct counter_map){ COUNTER_MAP_NOMAP, 0 }); 842e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 843e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher newh->new_number = (*handle)->new_number + num_rules; 844e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher newh->entries.size = (*handle)->entries.size + rules_size; 845e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher newh->hooknames = (*handle)->hooknames; 846e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 84730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if ((*handle)->cache_chain_heads) 84830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell free((*handle)->cache_chain_heads); 849e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher free(*handle); 850e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *handle = newh; 851e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 852e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return set_verdict(offset, rules_size, handle); 853e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 854e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 855e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int 856e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherdelete_rules(unsigned int num_rules, unsigned int rules_size, 857e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int offset, unsigned int num_rules_offset, 858e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_handle_t *handle) 859e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 860e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int i; 861e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 862e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (offset + rules_size > (*handle)->entries.size) { 863e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = EINVAL; 864e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 865e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 866e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 867e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Fix up entry points. */ 868e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher for (i = 0; i < NF_IP_NUMHOOKS; i++) { 869e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* In practice, we never delete up to a hook entry, 870e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher since the built-in chains are always first, 871e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher so these two are never equal */ 872e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if ((*handle)->info.hook_entry[i] >= offset + rules_size) 873e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*handle)->info.hook_entry[i] -= rules_size; 874e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher else if ((*handle)->info.hook_entry[i] > offset) { 875e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher fprintf(stderr, "ERROR: Deleting entry %u %u %u\n", 876e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher i, (*handle)->info.hook_entry[i], offset); 877e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher abort(); 878e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 879e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 880e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Underflow points to policy (terminal) rule in 881e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher built-in, so sequality is valid here (when deleting 882e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher the last rule). */ 883e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if ((*handle)->info.underflow[i] >= offset + rules_size) 884e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*handle)->info.underflow[i] -= rules_size; 885e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher else if ((*handle)->info.underflow[i] > offset) { 886e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher fprintf(stderr, "ERROR: Deleting uflow %u %u %u\n", 887e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher i, (*handle)->info.underflow[i], offset); 888e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher abort(); 889e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 890e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 891e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 892e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Move the rules down. */ 893e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher memmove((*handle)->entries.entries + offset, 894e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*handle)->entries.entries + offset + rules_size, 895e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*handle)->entries.size - (offset + rules_size)); 896e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 897e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Move the counter map down. */ 898e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher memmove(&(*handle)->counter_map[num_rules_offset], 899e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher &(*handle)->counter_map[num_rules_offset + num_rules], 900e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher sizeof(struct counter_map) 901e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * ((*handle)->new_number - (num_rules + num_rules_offset))); 902e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 903e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Fix numbers */ 904e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*handle)->new_number -= num_rules; 905e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*handle)->entries.size -= rules_size; 906e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 907e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return set_verdict(offset, -(int)rules_size, handle); 908e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 909e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 910e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int 911e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstandard_map(struct ipt_entry *e, int verdict) 912e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 913e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_standard_target *t; 914e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 915e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher t = (struct ipt_standard_target *)ipt_get_target(e); 916e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 917228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell if (t->target.u.target_size != sizeof(struct ipt_standard_target)) { 918e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = EINVAL; 919e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 920e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 921e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* memset for memcmp convenience on delete/replace */ 922228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell memset(t->target.u.user.name, 0, IPT_FUNCTION_MAXNAMELEN); 923228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell strcpy(t->target.u.user.name, IPT_STANDARD_TARGET); 924e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher t->verdict = verdict; 925e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 926e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 1; 927e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 9287e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell 929e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int 930e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchermap_target(const iptc_handle_t handle, 931e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry *e, 932e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int offset, 933e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry_target *old) 934e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 935e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry_target *t = ipt_get_target(e); 936e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 937e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Save old target (except data, which we don't change, except for 938e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher standard case, where we don't care). */ 939e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *old = *t; 940e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 941e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Maybe it's empty (=> fall through) */ 942228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell if (strcmp(t->u.user.name, "") == 0) 943e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return standard_map(e, offset + e->next_offset); 944e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Maybe it's a standard target name... */ 945228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell else if (strcmp(t->u.user.name, IPTC_LABEL_ACCEPT) == 0) 946e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return standard_map(e, -NF_ACCEPT - 1); 947228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell else if (strcmp(t->u.user.name, IPTC_LABEL_DROP) == 0) 948e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return standard_map(e, -NF_DROP - 1); 949228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell else if (strcmp(t->u.user.name, IPTC_LABEL_QUEUE) == 0) 950e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return standard_map(e, -NF_QUEUE - 1); 951228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell else if (strcmp(t->u.user.name, IPTC_LABEL_RETURN) == 0) 952e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return standard_map(e, IPT_RETURN); 953228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell else if (iptc_builtin(t->u.user.name, handle)) { 954e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Can't jump to builtins. */ 955e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = EINVAL; 956e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 957e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } else { 958e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Maybe it's an existing chain name. */ 95930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell struct chain_cache *c; 960e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 961228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell c = find_label(t->u.user.name, handle); 96230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (c) 96330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell return standard_map(e, entry2offset(handle, c->start)); 964e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 965e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 966e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Must be a module? If not, kernel will reject... */ 967e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* memset to all 0 for your memcmp convenience. */ 968228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell memset(t->u.user.name + strlen(t->u.user.name), 969e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 0, 970228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell IPT_FUNCTION_MAXNAMELEN - strlen(t->u.user.name)); 971e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 1; 972e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 973e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 974e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void 975e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherunmap_target(struct ipt_entry *e, struct ipt_entry_target *old) 976e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 977e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry_target *t = ipt_get_target(e); 978e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 979e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Save old target (except data, which we don't change, except for 980e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher standard case, where we don't care). */ 981e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *t = *old; 982e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 983e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 984e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Insert the entry `fw' in chain `chain' into position `rulenum'. */ 985e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint 986e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_insert_entry(const ipt_chainlabel chain, 987e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher const struct ipt_entry *e, 988e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int rulenum, 989e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_handle_t *handle) 990e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 99130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell unsigned int chainindex, offset; 992e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry_target old; 99330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell struct chain_cache *c; 994e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int ret; 995e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 996e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_fn = iptc_insert_entry; 99730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (!(c = find_label(chain, *handle))) { 998e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOENT; 999e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1000e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1001e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 100230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell chainindex = entry2index(*handle, c->start); 1003e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 100430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (index2entry(*handle, chainindex + rulenum) > c->end) { 1005e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = E2BIG; 1006e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1007e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1008e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher offset = index2offset(*handle, chainindex + rulenum); 1009e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1010e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Mapping target actually alters entry, but that's 1011e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher transparent to the caller. */ 1012e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!map_target(*handle, (struct ipt_entry *)e, offset, &old)) 1013e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1014e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1015e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher ret = insert_rules(1, e->next_offset, e, offset, 1016e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher chainindex + rulenum, rulenum == 0, handle); 1017e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unmap_target((struct ipt_entry *)e, &old); 1018e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return ret; 1019e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1020e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1021e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Atomically replace rule `rulenum' in `chain' with `fw'. */ 1022e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint 1023e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_replace_entry(const ipt_chainlabel chain, 1024e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher const struct ipt_entry *e, 1025e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int rulenum, 1026e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_handle_t *handle) 1027e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 102830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell unsigned int chainindex, offset; 1029e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry_target old; 103030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell struct chain_cache *c; 1031e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int ret; 1032e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1033e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_fn = iptc_replace_entry; 1034e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 103530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (!(c = find_label(chain, *handle))) { 1036e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOENT; 1037e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1038e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1039e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 104030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell chainindex = entry2index(*handle, c->start); 1041e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 104230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (index2entry(*handle, chainindex + rulenum) >= c->end) { 1043e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = E2BIG; 1044e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1045e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1046e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1047e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher offset = index2offset(*handle, chainindex + rulenum); 1048e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Replace = delete and insert. */ 1049e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!delete_rules(1, get_entry(*handle, offset)->next_offset, 1050e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher offset, chainindex + rulenum, handle)) 1051e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1052e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1053e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!map_target(*handle, (struct ipt_entry *)e, offset, &old)) 1054e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1055e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1056e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher ret = insert_rules(1, e->next_offset, e, offset, 1057e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher chainindex + rulenum, 1, handle); 1058e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unmap_target((struct ipt_entry *)e, &old); 1059e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return ret; 1060e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1061e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1062e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Append entry `fw' to chain `chain'. Equivalent to insert with 1063e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher rulenum = length of chain. */ 1064e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint 1065e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_append_entry(const ipt_chainlabel chain, 1066e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher const struct ipt_entry *e, 1067e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_handle_t *handle) 1068e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 106930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell struct chain_cache *c; 1070e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry_target old; 1071e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int ret; 1072e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1073e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_fn = iptc_append_entry; 107430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (!(c = find_label(chain, *handle))) { 1075e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOENT; 1076e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1077e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1078e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 107930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (!map_target(*handle, (struct ipt_entry *)e, 108030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell entry2offset(*handle, c->end), &old)) 1081e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1082e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 108330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell ret = insert_rules(1, e->next_offset, e, 108430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell entry2offset(*handle, c->end), 108530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell entry2index(*handle, c->end), 1086e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 0, handle); 1087e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unmap_target((struct ipt_entry *)e, &old); 1088e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return ret; 1089e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1090e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1091e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int 1092e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchermatch_different(const struct ipt_entry_match *a, 1093edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell const unsigned char *a_elems, 1094edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell const unsigned char *b_elems, 1095edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell unsigned char **maskptr) 1096e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 1097e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher const struct ipt_entry_match *b; 1098edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell unsigned int i; 1099e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1100e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Offset of b is the same as a. */ 110130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell b = (void *)b_elems + ((unsigned char *)a - a_elems); 1102e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1103228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell if (a->u.match_size != b->u.match_size) 1104e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 1; 1105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1106228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell if (strcmp(a->u.user.name, b->u.user.name) != 0) 1107e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 1; 1108e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1109edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell *maskptr += sizeof(*a); 1110edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell 1111228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell for (i = 0; i < a->u.match_size - sizeof(*a); i++) 1112edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0) 1113edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell return 1; 1114edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell *maskptr += i; 1115edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell return 0; 1116edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell} 1117edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell 1118edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russellstatic inline int 1119edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russelltarget_different(const unsigned char *a_targdata, 1120edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell const unsigned char *b_targdata, 1121edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell unsigned int tdatasize, 1122edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell const unsigned char *mask) 1123edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell{ 1124edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell unsigned int i; 1125edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell for (i = 0; i < tdatasize; i++) 1126edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell if (((a_targdata[i] ^ b_targdata[i]) & mask[i]) != 0) 112790e712a00913fe2a2f885142439c392392dc08a8Rusty Russell return 1; 1128e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1129e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1130e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1131e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1132e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int 1133edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russellis_same(const struct ipt_entry *a, const struct ipt_entry *b, 1134edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell unsigned char *matchmask) 1135e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 1136e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int i; 1137e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry_target *ta, *tb; 1138edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell unsigned char *mptr; 1139e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1140edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell /* Always compare head structures: ignore mask here. */ 1141e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (a->ip.src.s_addr != b->ip.src.s_addr 1142e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || a->ip.dst.s_addr != b->ip.dst.s_addr 1143e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || a->ip.smsk.s_addr != b->ip.smsk.s_addr 1144e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || a->ip.smsk.s_addr != b->ip.smsk.s_addr 1145e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || a->ip.proto != b->ip.proto 1146e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || a->ip.flags != b->ip.flags 1147e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || a->ip.invflags != b->ip.invflags) 1148e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1149e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1150e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher for (i = 0; i < IFNAMSIZ; i++) { 1151e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (a->ip.iniface_mask[i] != b->ip.iniface_mask[i]) 1152e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1153e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if ((a->ip.iniface[i] & a->ip.iniface_mask[i]) 1154e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher != (b->ip.iniface[i] & b->ip.iniface_mask[i])) 1155e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1156e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (a->ip.outiface_mask[i] != b->ip.outiface_mask[i]) 1157e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1158e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if ((a->ip.outiface[i] & a->ip.outiface_mask[i]) 1159e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher != (b->ip.outiface[i] & b->ip.outiface_mask[i])) 1160e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1161e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1162e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1163e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (a->nfcache != b->nfcache 1164e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || a->target_offset != b->target_offset 1165e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || a->next_offset != b->next_offset) 1166e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1167e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1168edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell mptr = matchmask + sizeof(struct ipt_entry); 1169edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell if (IPT_MATCH_ITERATE(a, match_different, a->elems, b->elems, &mptr)) 1170e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1171e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1172e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher ta = ipt_get_target((struct ipt_entry *)a); 1173e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher tb = ipt_get_target((struct ipt_entry *)b); 1174228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell if (ta->u.target_size != tb->u.target_size) 1175e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1176228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell if (strcmp(ta->u.user.name, tb->u.user.name) != 0) 1177e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1178edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell 1179ca92443e5a2b6430e334900058b341b440d385d9Marc Boucher mptr += sizeof(*ta); 1180edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell if (target_different(ta->data, tb->data, 1181228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell ta->u.target_size - sizeof(*ta), mptr)) 1182edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell return 0; 1183edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell 118490e712a00913fe2a2f885142439c392392dc08a8Rusty Russell return 1; 1185e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1186e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1187e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Delete the first rule in `chain' which matches `fw'. */ 1188e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint 1189e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_delete_entry(const ipt_chainlabel chain, 1190e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher const struct ipt_entry *origfw, 1191edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell unsigned char *matchmask, 1192e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_handle_t *handle) 1193e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 119430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell unsigned int offset; 119530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell struct chain_cache *c; 1196e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry *e, *fw; 1197e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1198e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_fn = iptc_delete_entry; 119930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (!(c = find_label(chain, *handle))) { 1200e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOENT; 1201e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1202e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1203e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1204e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher fw = malloc(origfw->next_offset); 1205e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (fw == NULL) { 1206e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOMEM; 1207e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1208e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1209e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 121030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell for (offset = entry2offset(*handle, c->start); 121130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell offset < entry2offset(*handle, c->end); 121230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell offset += e->next_offset) { 1213e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry_target discard; 1214e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1215e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher memcpy(fw, origfw, origfw->next_offset); 1216e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1217e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* FIXME: handle this in is_same --RR */ 1218e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!map_target(*handle, fw, offset, &discard)) { 1219e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher free(fw); 1220e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1221e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1222e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher e = get_entry(*handle, offset); 1223e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1224e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if 0 1225e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("Deleting:\n"); 1226e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher dump_entry(newe); 1227e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif 1228edf14cf4b5edb148d7473f067d95e7bd1316900bRusty Russell if (is_same(e, fw, matchmask)) { 1229e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int ret; 1230e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher ret = delete_rules(1, e->next_offset, 1231e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher offset, entry2index(*handle, e), 1232e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher handle); 1233e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher free(fw); 1234e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return ret; 1235e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1236e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1237e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1238e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher free(fw); 1239e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOENT; 1240e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 12417e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell} 1242e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1243e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Delete the rule in position `rulenum' in `chain'. */ 1244e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint 1245e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_delete_num_entry(const ipt_chainlabel chain, 1246e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int rulenum, 1247e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_handle_t *handle) 1248e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 1249e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int index; 1250e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int ret; 1251e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry *e; 125230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell struct chain_cache *c; 1253e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1254e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_fn = iptc_delete_num_entry; 125530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (!(c = find_label(chain, *handle))) { 1256e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOENT; 1257e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1258e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1259e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 126030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell index = entry2index(*handle, c->start) + rulenum; 1261e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 126230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (index >= entry2index(*handle, c->end)) { 1263e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = E2BIG; 1264e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1265e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1266e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1267e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher e = index2entry(*handle, index); 1268e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (e == NULL) { 1269e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = EINVAL; 1270e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1271e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1272e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1273e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher ret = delete_rules(1, e->next_offset, entry2offset(*handle, e), 1274e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher index, handle); 1275e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return ret; 1276e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1277e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1278e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Check the packet `fw' on chain `chain'. Returns the verdict, or 1279e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher NULL and sets errno. */ 1280e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char * 1281e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_check_packet(const ipt_chainlabel chain, 1282e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry *entry, 1283e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_handle_t *handle) 1284e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 1285e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOSYS; 1286e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return NULL; 1287e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1288e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1289e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Flushes the entries in the given chain (ie. empties chain). */ 1290e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint 1291e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_flush_entries(const ipt_chainlabel chain, iptc_handle_t *handle) 1292e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 129330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell unsigned int startindex, endindex; 129430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell struct chain_cache *c; 1295e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int ret; 1296e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1297e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_fn = iptc_flush_entries; 129830fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (!(c = find_label(chain, *handle))) { 1299e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOENT; 1300e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1301e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 130230fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell startindex = entry2index(*handle, c->start); 130330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell endindex = entry2index(*handle, c->end); 1304e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1305e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher ret = delete_rules(endindex - startindex, 130630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell (char *)c->end - (char *)c->start, 130730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell entry2offset(*handle, c->start), startindex, 1308e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher handle); 1309e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return ret; 1310e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1311e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1312e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Zeroes the counters in a chain. */ 1313e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint 1314e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_zero_entries(const ipt_chainlabel chain, iptc_handle_t *handle) 1315e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 1316e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int i, end; 131730fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell struct chain_cache *c; 13187e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell 131930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (!(c = find_label(chain, *handle))) { 1320e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOENT; 1321e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1322e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1323e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 132430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell i = entry2index(*handle, c->start); 132530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell end = entry2index(*handle, c->end); 1326e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1327e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher for (; i <= end; i++) { 1328e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if ((*handle)->counter_map[i].maptype ==COUNTER_MAP_NORMAL_MAP) 1329e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*handle)->counter_map[i].maptype = COUNTER_MAP_ZEROED; 1330e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1331175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell set_changed(*handle); 1332e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1333e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 1; 1334e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1335e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1336e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Creates a new chain. */ 1337e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* To create a chain, create two rules: error node and unconditional 1338e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * return. */ 1339e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint 1340e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_create_chain(const ipt_chainlabel chain, iptc_handle_t *handle) 1341e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 1342e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int ret; 1343e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct { 1344e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry head; 1345e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_error_target name; 1346e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry ret; 1347e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_standard_target target; 1348e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } newc; 1349e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1350e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_fn = iptc_create_chain; 1351e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1352e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* find_label doesn't cover built-in targets: DROP, ACCEPT, 1353e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher QUEUE, RETURN. */ 135430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (find_label(chain, *handle) 1355e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || strcmp(chain, IPTC_LABEL_DROP) == 0 1356e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || strcmp(chain, IPTC_LABEL_ACCEPT) == 0 1357e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || strcmp(chain, IPTC_LABEL_QUEUE) == 0 1358e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || strcmp(chain, IPTC_LABEL_RETURN) == 0) { 1359e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = EEXIST; 1360e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1361e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1362e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1363e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (strlen(chain)+1 > sizeof(ipt_chainlabel)) { 1364e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = EINVAL; 1365e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1366e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1367e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1368e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher memset(&newc, 0, sizeof(newc)); 1369e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher newc.head.target_offset = sizeof(struct ipt_entry); 1370e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher newc.head.next_offset 1371e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher = sizeof(struct ipt_entry) + sizeof(struct ipt_error_target); 1372228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell strcpy(newc.name.t.u.user.name, IPT_ERROR_TARGET); 1373228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell newc.name.t.u.target_size = sizeof(struct ipt_error_target); 1374e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher strcpy(newc.name.error, chain); 1375e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1376e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher newc.ret.target_offset = sizeof(struct ipt_entry); 1377e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher newc.ret.next_offset 1378e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher = sizeof(struct ipt_entry)+sizeof(struct ipt_standard_target); 1379228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell strcpy(newc.target.target.u.user.name, IPT_STANDARD_TARGET); 1380228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell newc.target.target.u.target_size = sizeof(struct ipt_standard_target); 1381e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher newc.target.verdict = IPT_RETURN; 1382e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1383e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Add just before terminal entry */ 1384e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher ret = insert_rules(2, sizeof(newc), &newc.head, 1385e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher index2offset(*handle, (*handle)->new_number - 1), 1386e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*handle)->new_number - 1, 1387e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 0, handle); 1388e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return ret; 1389e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1390e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1391e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic int 1392e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchercount_ref(struct ipt_entry *e, unsigned int offset, unsigned int *ref) 1393e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 1394e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_standard_target *t; 1395e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1396228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell if (strcmp(ipt_get_target(e)->u.user.name, IPT_STANDARD_TARGET) == 0) { 1397e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher t = (struct ipt_standard_target *)ipt_get_target(e); 1398e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1399e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (t->verdict == offset) 1400e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*ref)++; 1401e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1402e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1403e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1404e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1405e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1406e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get the number of references to this chain. */ 1407e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint 1408e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_get_references(unsigned int *ref, const ipt_chainlabel chain, 1409e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_handle_t *handle) 1410e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 141130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell struct chain_cache *c; 1412e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 141330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (!(c = find_label(chain, *handle))) { 1414e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOENT; 1415e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1416e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1417e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1418e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *ref = 0; 1419e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher IPT_ENTRY_ITERATE((*handle)->entries.entries, 1420e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*handle)->entries.size, 142130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell count_ref, entry2offset(*handle, c->start), ref); 1422e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 1; 1423e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1424e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1425e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Deletes a chain. */ 1426e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint 1427e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_delete_chain(const ipt_chainlabel chain, iptc_handle_t *handle) 1428e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 142930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell unsigned int labelidx, labeloff; 1430e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int references; 143130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell struct chain_cache *c; 1432e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int ret; 1433e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1434e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!iptc_get_references(&references, chain, handle)) 1435e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 14367e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell 1437e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_fn = iptc_delete_chain; 1438e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1439e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (iptc_builtin(chain, *handle)) { 1440e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = EINVAL; 1441e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1442e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1443e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1444e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (references > 0) { 1445e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = EMLINK; 1446e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1447e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1448e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 144930fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (!(c = find_label(chain, *handle))) { 1450e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOENT; 1451e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1452e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1453e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 145430fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if ((void *)c->start != c->end) { 1455e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOTEMPTY; 1456e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1457e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1458e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1459e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Need label index: preceeds chain start */ 146030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell labelidx = entry2index(*handle, c->start) - 1; 1461e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher labeloff = index2offset(*handle, labelidx); 1462e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1463e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher ret = delete_rules(2, 1464e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher get_entry(*handle, labeloff)->next_offset 146530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell + c->start->next_offset, 1466e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher labeloff, labelidx, handle); 1467e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return ret; 1468e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1469e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1470e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Renames a chain. */ 1471e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint iptc_rename_chain(const ipt_chainlabel oldname, 1472e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher const ipt_chainlabel newname, 1473e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_handle_t *handle) 1474e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 147530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell unsigned int labeloff, labelidx; 147630fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell struct chain_cache *c; 1477e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_error_target *t; 1478e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1479e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_fn = iptc_rename_chain; 1480e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1481e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* find_label doesn't cover built-in targets: DROP, ACCEPT 1482e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher RETURN. */ 148330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (find_label(newname, *handle) 1484e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || strcmp(newname, IPTC_LABEL_DROP) == 0 1485e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || strcmp(newname, IPTC_LABEL_ACCEPT) == 0 1486e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || strcmp(newname, IPTC_LABEL_RETURN) == 0) { 1487e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = EEXIST; 1488e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1489e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1490e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 149130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if (!(c = find_label(oldname, *handle)) 1492e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || iptc_builtin(oldname, *handle)) { 1493e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOENT; 1494e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1495e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1496e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1497e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (strlen(newname)+1 > sizeof(ipt_chainlabel)) { 1498e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = EINVAL; 1499e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1500e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1501e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1502e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Need label index: preceeds chain start */ 150330fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell labelidx = entry2index(*handle, c->start) - 1; 1504e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher labeloff = index2offset(*handle, labelidx); 1505e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1506e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher t = (struct ipt_error_target *) 1507e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher ipt_get_target(get_entry(*handle, labeloff)); 1508e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1509e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher memset(t->error, 0, sizeof(t->error)); 1510e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher strcpy(t->error, newname); 1511175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell set_changed(*handle); 1512e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1513e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 1; 1514e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1515e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1516e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Sets the policy on a built-in chain. */ 1517e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint 1518e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_set_policy(const ipt_chainlabel chain, 1519e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher const ipt_chainlabel policy, 1520e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_handle_t *handle) 1521e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 1522e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int hook; 1523e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int policyoff; 1524e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry *e; 1525e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_standard_target *t; 1526e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1527c8264991454b5e77279830736f80ea3153b6f814Marc Boucher iptc_fn = iptc_set_policy; 1528e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Figure out which chain. */ 1529e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher hook = iptc_builtin(chain, *handle); 1530e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (hook == 0) { 1531c8264991454b5e77279830736f80ea3153b6f814Marc Boucher errno = ENOENT; 1532e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1533e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } else 1534e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher hook--; 1535e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1536e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher policyoff = get_chain_end(*handle, (*handle)->info.hook_entry[hook]); 1537e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (policyoff != (*handle)->info.underflow[hook]) { 1538e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("ERROR: Policy for `%s' offset %u != underflow %u\n", 1539e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher chain, policyoff, (*handle)->info.underflow[hook]); 1540e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1541e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1542e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1543e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher e = get_entry(*handle, policyoff); 1544e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher t = (struct ipt_standard_target *)ipt_get_target(e); 1545e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1546e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (strcmp(policy, IPTC_LABEL_ACCEPT) == 0) 1547e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher t->verdict = -NF_ACCEPT - 1; 1548e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher else if (strcmp(policy, IPTC_LABEL_DROP) == 0) 1549e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher t->verdict = -NF_DROP - 1; 1550e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher else { 1551e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = EINVAL; 1552e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1553e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1554e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*handle)->counter_map[entry2index(*handle, e)] 1555e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher = ((struct counter_map){ COUNTER_MAP_NOMAP, 0 }); 1556175f64177743e5a417e98d483ef995bf7151f3bcRusty Russell set_changed(*handle); 1557e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1558e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 1; 1559e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1560e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1561e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Without this, on gcc 2.7.2.3, we get: 1562e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher libiptc.c: In function `iptc_commit': 1563e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher libiptc.c:833: fixed or forbidden register was spilled. 1564e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher This may be due to a compiler bug or to impossible asm 1565e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher statements or clauses. 1566e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher*/ 1567e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void 1568e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchersubtract_counters(struct ipt_counters *answer, 1569e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher const struct ipt_counters *a, 1570e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher const struct ipt_counters *b) 1571e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 1572e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher answer->pcnt = a->pcnt - b->pcnt; 1573e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher answer->bcnt = a->bcnt - b->bcnt; 1574e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1575e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1576e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint 1577e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_commit(iptc_handle_t *handle) 1578e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 1579e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Replace, then map back the counters. */ 1580e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_replace *repl; 1581e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_counters_info *newcounters; 1582e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int i; 1583e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher size_t counterlen 1584e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher = sizeof(struct ipt_counters_info) 1585e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher + sizeof(struct ipt_counters) * (*handle)->new_number; 1586e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1587e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher CHECK(*handle); 1588e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#if 0 1589e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher dump_entries(*handle); 1590e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#endif 1591e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1592e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Don't commit if nothing changed. */ 1593e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!(*handle)->changed) 1594e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher goto finished; 1595e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1596e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher repl = malloc(sizeof(*repl) + (*handle)->entries.size); 1597e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!repl) { 1598e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOMEM; 1599e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1600e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1601e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1602e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* These are the old counters we will get from kernel */ 1603e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher repl->counters = malloc(sizeof(struct ipt_counters) 1604e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * (*handle)->info.num_entries); 1605e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!repl->counters) { 1606e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher free(repl); 1607e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOMEM; 1608e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1609e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 16107e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell 1611e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* These are the counters we're going to put back, later. */ 1612e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher newcounters = malloc(counterlen); 1613e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!newcounters) { 1614e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher free(repl->counters); 1615e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher free(repl); 1616e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher errno = ENOMEM; 1617e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1618e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1619e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1620e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher strcpy(repl->name, (*handle)->info.name); 1621e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher repl->num_entries = (*handle)->new_number; 1622e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher repl->size = (*handle)->entries.size; 1623e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher memcpy(repl->hook_entry, (*handle)->info.hook_entry, 1624e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher sizeof(repl->hook_entry)); 1625e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher memcpy(repl->underflow, (*handle)->info.underflow, 1626e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher sizeof(repl->underflow)); 1627e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher repl->num_counters = (*handle)->info.num_entries; 1628e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher repl->valid_hooks = (*handle)->info.valid_hooks; 1629e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher memcpy(repl->entries, (*handle)->entries.entries, 1630e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*handle)->entries.size); 1631e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1632e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (setsockopt(sockfd, IPPROTO_IP, IPT_SO_SET_REPLACE, repl, 1633e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher sizeof(*repl) + (*handle)->entries.size) < 0) { 1634e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher free(repl->counters); 1635e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher free(repl); 1636e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher free(newcounters); 1637e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1638e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1639e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1640e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Put counters back. */ 1641e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher strcpy(newcounters->name, (*handle)->info.name); 1642e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher newcounters->num_counters = (*handle)->new_number; 1643e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher for (i = 0; i < (*handle)->new_number; i++) { 1644e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int mappos = (*handle)->counter_map[i].mappos; 1645e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher switch ((*handle)->counter_map[i].maptype) { 1646e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher case COUNTER_MAP_NOMAP: 1647e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher newcounters->counters[i] 1648e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher = ((struct ipt_counters){ 0, 0 }); 1649e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher break; 1650e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1651e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher case COUNTER_MAP_NORMAL_MAP: 1652e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Original read: X. 1653e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Atomic read on replacement: X + Y. 1654e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Currently in kernel: Z. 1655e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Want in kernel: X + Y + Z. 1656e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * => Add in X + Y 1657e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * => Add in replacement read. 1658e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher */ 1659e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher newcounters->counters[i] = repl->counters[mappos]; 1660e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher break; 1661e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1662e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher case COUNTER_MAP_ZEROED: 1663e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Original read: X. 1664e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Atomic read on replacement: X + Y. 1665e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Currently in kernel: Z. 1666e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * Want in kernel: Y + Z. 1667e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * => Add in Y. 1668e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * => Add in (replacement read - original read). 1669e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher */ 1670e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher subtract_counters(&newcounters->counters[i], 1671e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher &repl->counters[mappos], 1672e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher &index2entry(*handle, i)->counters); 1673e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher break; 1674e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1675e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1676e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 16777e53bf9c2a697abdb6f1385557338423a86612a3Rusty Russell if (setsockopt(sockfd, IPPROTO_IP, IPT_SO_SET_ADD_COUNTERS, 1678e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher newcounters, counterlen) < 0) { 1679e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher free(repl->counters); 1680e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher free(repl); 1681e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher free(newcounters); 1682e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1683e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1684e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1685e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher free(repl->counters); 1686e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher free(repl); 1687e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher free(newcounters); 1688e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1689e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher finished: 169030fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell if ((*handle)->cache_chain_heads) 169130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell free((*handle)->cache_chain_heads); 1692e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher free(*handle); 1693e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *handle = NULL; 1694e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 1; 1695e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1696e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1697e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Get raw socket. */ 1698e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherint 1699e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_get_raw_socket() 1700e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 1701e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return sockfd; 1702e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1703e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1704e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Translates errno numbers into more human-readable form than strerror. */ 1705e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherconst char * 1706e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucheriptc_strerror(int err) 1707e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 1708e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int i; 1709e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct table_struct { 1710e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher void *fn; 1711e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int err; 1712e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher const char *message; 1713e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } table [] = 1714e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher { { NULL, 0, "Incompatible with this kernel" }, 1715e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" }, 1716e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher { NULL, ENOSYS, "Will be implemented real soon. I promise." }, 1717e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher { NULL, ENOMEM, "Memory allocation problem" }, 1718e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher { iptc_init, EPERM, "Permission denied (you must be root)" }, 1719e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher { iptc_init, EINVAL, "Module is wrong version" }, 1720e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher { iptc_delete_chain, ENOTEMPTY, "Chain is not empty" }, 1721e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher { iptc_delete_chain, EINVAL, "Can't delete built-in chain" }, 1722e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher { iptc_delete_chain, EMLINK, 1723e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher "Can't delete chain with references left" }, 1724e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher { iptc_create_chain, EEXIST, "Chain already exists" }, 1725e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher { iptc_insert_entry, E2BIG, "Index of insertion too big" }, 1726e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher { iptc_replace_entry, E2BIG, "Index of replacement too big" }, 1727e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher { iptc_delete_num_entry, E2BIG, "Index of deletion too big" }, 1728e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher { iptc_insert_entry, ELOOP, "Loop found in table" }, 1729e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher { iptc_insert_entry, EINVAL, "Target problem" }, 1730e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* EINVAL for CHECK probably means bad interface. */ 1731e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher { iptc_check_packet, EINVAL, 1732c8264991454b5e77279830736f80ea3153b6f814Marc Boucher "Bad arguments (does that interface exist?)" }, 1733e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* ENOENT for DELETE probably means no matching rule */ 1734e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher { iptc_delete_entry, ENOENT, 1735c8264991454b5e77279830736f80ea3153b6f814Marc Boucher "Bad rule (does a matching rule exist in that chain?)" }, 1736c8264991454b5e77279830736f80ea3153b6f814Marc Boucher { iptc_set_policy, ENOENT, 1737c8264991454b5e77279830736f80ea3153b6f814Marc Boucher "Bad built-in chain name" }, 1738c8264991454b5e77279830736f80ea3153b6f814Marc Boucher { iptc_set_policy, EINVAL, 1739c8264991454b5e77279830736f80ea3153b6f814Marc Boucher "Bad policy name" }, 1740e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher { NULL, ENOENT, "No extended target/match by that name" } 1741e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher }; 1742e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1743e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) { 1744e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if ((!table[i].fn || table[i].fn == iptc_fn) 1745e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher && table[i].err == err) 1746e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return table[i].message; 1747e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1748e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1749e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return strerror(err); 1750e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1751e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1752e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/***************************** DEBUGGING ********************************/ 1753e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int 1754e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherunconditional(const struct ipt_ip *ip) 1755e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 1756e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int i; 1757e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1758e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher for (i = 0; i < sizeof(*ip)/sizeof(u_int32_t); i++) 1759e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (((u_int32_t *)ip)[i]) 1760e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1761e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1762e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 1; 1763e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1764e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1765e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int 1766e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchercheck_match(const struct ipt_entry_match *m, unsigned int *off) 1767e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 1768228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell assert(m->u.match_size >= sizeof(struct ipt_entry_match)); 1769228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell assert(IPT_ALIGN(m->u.match_size) == m->u.match_size); 1770e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1771228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell (*off) += m->u.match_size; 1772e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1773e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1774e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1775e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic inline int 1776e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchercheck_entry(const struct ipt_entry *e, unsigned int *i, unsigned int *off, 1777e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int user_offset, int *was_return, 1778e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher iptc_handle_t h) 1779e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 1780e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int toff; 1781e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_standard_target *t; 1782e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1783e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(e->target_offset >= sizeof(struct ipt_entry)); 1784e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(e->next_offset >= e->target_offset 1785e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher + sizeof(struct ipt_entry_target)); 1786e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher toff = sizeof(struct ipt_entry); 1787e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher IPT_MATCH_ITERATE(e, check_match, &toff); 1788e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1789e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(toff == e->target_offset); 1790e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1791e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher t = (struct ipt_standard_target *) 1792e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher ipt_get_target((struct ipt_entry *)e); 1793228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell /* next_offset will have to be multiple of entry alignment. */ 1794228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell assert(e->next_offset == IPT_ALIGN(e->next_offset)); 1795228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell assert(e->target_offset == IPT_ALIGN(e->target_offset)); 1796228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell assert(t->target.u.target_size == IPT_ALIGN(t->target.u.target_size)); 1797228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell assert(!iptc_is_chain(t->target.u.user.name, h)); 1798228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell 1799228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell if (strcmp(t->target.u.user.name, IPT_STANDARD_TARGET) == 0) { 1800228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell assert(t->target.u.target_size 1801e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher == IPT_ALIGN(sizeof(struct ipt_standard_target))); 1802e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1803e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(t->verdict == -NF_DROP-1 1804e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || t->verdict == -NF_ACCEPT-1 1805e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || t->verdict == IPT_RETURN 1806e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || t->verdict < (int)h->entries.size); 1807e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1808e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (t->verdict >= 0) { 1809e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry *te = get_entry(h, t->verdict); 1810e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int idx; 1811e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1812e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher idx = entry2index(h, te); 1813228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell assert(strcmp(ipt_get_target(te)->u.user.name, 1814e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher IPT_ERROR_TARGET) 1815e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher != 0); 1816e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(te != e); 1817e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1818e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Prior node must be error node, or this node. */ 1819e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(t->verdict == entry2offset(h, e)+e->next_offset 1820e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher || strcmp(ipt_get_target(index2entry(h, idx-1)) 1821228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell ->u.user.name, IPT_ERROR_TARGET) 1822e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher == 0); 1823e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1824e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1825e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (t->verdict == IPT_RETURN 1826e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher && unconditional(&e->ip) 1827e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher && e->target_offset == sizeof(*e)) 1828e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *was_return = 1; 1829e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher else 1830e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *was_return = 0; 1831228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell } else if (strcmp(t->target.u.user.name, IPT_ERROR_TARGET) == 0) { 1832228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell assert(t->target.u.target_size 1833e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher == IPT_ALIGN(sizeof(struct ipt_error_target))); 1834e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1835e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* If this is in user area, previous must have been return */ 1836e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (*off > user_offset) 1837e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(*was_return); 1838e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1839e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *was_return = 0; 1840e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1841e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher else *was_return = 0; 1842e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1843e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (*off == user_offset) 1844228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell assert(strcmp(t->target.u.user.name, IPT_ERROR_TARGET) == 0); 1845e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1846e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*off) += e->next_offset; 1847e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher (*i)++; 1848e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 0; 1849e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 1850e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 185130fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#ifndef NDEBUG 1852e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Do every conceivable sanity check on the handle */ 1853e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void 1854e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherdo_check(iptc_handle_t h, unsigned int line) 1855e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 1856e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int i, n; 1857e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int user_offset; /* Offset of first user chain */ 1858e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int was_return; 1859e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1860e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(h->changed == 0 || h->changed == 1); 1861e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (strcmp(h->info.name, "filter") == 0) { 1862e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(h->info.valid_hooks 1863e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher == (1 << NF_IP_LOCAL_IN 1864e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher | 1 << NF_IP_FORWARD 1865e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher | 1 << NF_IP_LOCAL_OUT)); 1866e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1867e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Hooks should be first three */ 1868e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(h->info.hook_entry[NF_IP_LOCAL_IN] == 0); 1869e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1870e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher n = get_chain_end(h, 0); 1871e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher n += get_entry(h, n)->next_offset; 1872e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(h->info.hook_entry[NF_IP_FORWARD] == n); 1873e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1874e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher n = get_chain_end(h, n); 1875e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher n += get_entry(h, n)->next_offset; 1876e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n); 1877e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1878e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT]; 1879e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } else if (strcmp(h->info.name, "nat") == 0) { 1880e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(h->info.valid_hooks 1881e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher == (1 << NF_IP_PRE_ROUTING 1882e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher | 1 << NF_IP_POST_ROUTING 1883e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher | 1 << NF_IP_LOCAL_OUT)); 1884e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1885e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0); 1886e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1887e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher n = get_chain_end(h, 0); 1888e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher n += get_entry(h, n)->next_offset; 1889e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(h->info.hook_entry[NF_IP_POST_ROUTING] == n); 1890e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1891e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher n = get_chain_end(h, n); 1892e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher n += get_entry(h, n)->next_offset; 1893e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n); 1894e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1895e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT]; 1896e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } else if (strcmp(h->info.name, "mangle") == 0) { 1897e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(h->info.valid_hooks 1898e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher == (1 << NF_IP_PRE_ROUTING 1899e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher | 1 << NF_IP_LOCAL_OUT)); 1900e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1901e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Hooks should be first three */ 1902e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(h->info.hook_entry[NF_IP_PRE_ROUTING] == 0); 1903e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1904e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher n = get_chain_end(h, 0); 1905e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher n += get_entry(h, n)->next_offset; 1906e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(h->info.hook_entry[NF_IP_LOCAL_OUT] == n); 1907e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1908e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher user_offset = h->info.hook_entry[NF_IP_LOCAL_OUT]; 1909e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } else 1910e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher abort(); 1911e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1912e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* User chain == end of last builtin + policy entry */ 1913e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher user_offset = get_chain_end(h, user_offset); 1914e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher user_offset += get_entry(h, user_offset)->next_offset; 1915e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1916e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Overflows should be end of entry chains, and unconditional 1917e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher policy nodes. */ 1918e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher for (i = 0; i < NF_IP_NUMHOOKS; i++) { 1919e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_entry *e; 1920e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_standard_target *t; 1921e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1922e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!(h->info.valid_hooks & (1 << i))) 1923e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher continue; 1924e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(h->info.underflow[i] 1925e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher == get_chain_end(h, h->info.hook_entry[i])); 1926e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1927e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher e = get_entry(h, get_chain_end(h, h->info.hook_entry[i])); 1928e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(unconditional(&e->ip)); 1929e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(e->target_offset == sizeof(*e)); 1930e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(e->next_offset == sizeof(*e) + sizeof(*t)); 1931e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher t = (struct ipt_standard_target *)ipt_get_target(e); 1932e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1933228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell assert(strcmp(t->target.u.user.name, IPT_STANDARD_TARGET)==0); 1934e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(t->verdict == -NF_DROP-1 || t->verdict == -NF_ACCEPT-1); 1935e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1936e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Hooks and underflows must be valid entries */ 1937e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher entry2index(h, get_entry(h, h->info.hook_entry[i])); 1938e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher entry2index(h, get_entry(h, h->info.underflow[i])); 1939e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 1940e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1941e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(h->info.size 1942e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher >= h->info.num_entries * (sizeof(struct ipt_entry) 1943e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher +sizeof(struct ipt_standard_target))); 1944e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1945e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(h->entries.size 1946e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher >= (h->new_number 1947e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher * (sizeof(struct ipt_entry) 1948e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher + sizeof(struct ipt_standard_target)))); 1949e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(strcmp(h->info.name, h->entries.name) == 0); 1950e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1951e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher i = 0; n = 0; 1952e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher was_return = 0; 1953e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Check all the entries. */ 1954e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher IPT_ENTRY_ITERATE(h->entries.entries, h->entries.size, 1955e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher check_entry, &i, &n, user_offset, &was_return, h); 1956e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1957e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(i == h->new_number); 1958e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher assert(n == h->entries.size); 1959e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1960e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Final entry must be error node */ 1961228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell assert(strcmp(ipt_get_target(index2entry(h, h->new_number-1)) 1962228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell ->u.user.name, 1963e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher IPT_ERROR_TARGET) == 0); 1964e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 196530fd6e5d45e6013f4df10a226787c7a9f49369c1Rusty Russell#endif /*NDEBUG*/ 1966