From 4f43138adebf493ee6484e9bb4196b94f2ad2f15 Mon Sep 17 00:00:00 2001 From: "Alexander V. Chernikov" Date: Mon, 11 Aug 2014 18:09:37 +0000 Subject: [PATCH] * Add the abilify to lock/unlock given table from changes. Example: # ipfw table si lock # ipfw table si info +++ table(si), set(0) +++ kindex: 0, type: cidr, locked valtype: number, references: 0 algorithm: cidr:radix items: 0, size: 288 # ipfw table si add 4.5.6.7 ignored: 4.5.6.7/32 0 ipfw: Adding record failed: table is locked # ipfw table si unlock # ipfw table si add 4.5.6.7 added: 4.5.6.7/32 0 # ipfw table si lock # ipfw table si delete 4.5.6.7 ignored: 4.5.6.7/32 0 ipfw: Deleting record failed: table is locked # ipfw table si unlock # ipfw table si delete 4.5.6.7 deleted: 4.5.6.7/32 0 --- sbin/ipfw/ipfw2.h | 2 ++ sbin/ipfw/tables.c | 42 ++++++++++++++++++++++++++++++---- sys/netinet/ip_fw.h | 11 ++++++--- sys/netpfil/ipfw/ip_fw_table.c | 16 ++++++++++++- 4 files changed, 62 insertions(+), 9 deletions(-) diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h index 2d78597767ae..d15df7e8f0fe 100644 --- a/sbin/ipfw/ipfw2.h +++ b/sbin/ipfw/ipfw2.h @@ -225,6 +225,8 @@ enum tokens { TOK_TALIST, TOK_FTYPE, TOK_ATOMIC, + TOK_LOCK, + TOK_UNLOCK, }; /* * the following macro returns an error message if we run out of diff --git a/sbin/ipfw/tables.c b/sbin/ipfw/tables.c index acb280fc21f1..b095f9196101 100644 --- a/sbin/ipfw/tables.c +++ b/sbin/ipfw/tables.c @@ -59,6 +59,7 @@ static int table_do_swap(ipfw_obj_header *oh, char *second); static void table_create(ipfw_obj_header *oh, int ac, char *av[]); static void table_modify(ipfw_obj_header *oh, int ac, char *av[]); static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]); +static void table_lock(ipfw_obj_header *oh, int lock); static int table_swap(ipfw_obj_header *oh, char *second); static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i); static int table_show_info(ipfw_xtable_info *i, void *arg); @@ -115,6 +116,8 @@ static struct _s_x tablecmds[] = { { "list", TOK_LIST }, { "lookup", TOK_LOOKUP }, { "atomic", TOK_ATOMIC }, + { "lock", TOK_LOCK }, + { "unlock", TOK_UNLOCK }, { NULL, 0 } }; @@ -240,6 +243,10 @@ ipfw_table_handler(int ac, char *av[]) NEED1("second table name required"); table_swap(&oh, *av); break; + case TOK_LOCK: + case TOK_UNLOCK: + table_lock(&oh, (tcmd == TOK_LOCK)); + break; case TOK_DETAIL: case TOK_INFO: arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL; @@ -297,6 +304,7 @@ static struct _s_x tablenewcmds[] = { { "valtype", TOK_VALTYPE }, { "algo", TOK_ALGO }, { "limit", TOK_LIMIT }, + { "locked", TOK_LOCK }, { NULL, 0 } }; @@ -440,6 +448,9 @@ table_create(ipfw_obj_header *oh, int ac, char *av[]) strlcpy(xi.algoname, *av, sizeof(xi.algoname)); ac--; av++; break; + case TOK_LOCK: + xi.flags |= IPFW_TGFLAGS_LOCKED; + break; } } @@ -485,10 +496,6 @@ table_modify(ipfw_obj_header *oh, int ac, char *av[]) sz = sizeof(tbuf); memset(&xi, 0, sizeof(xi)); - /* Set some defaults to preserve compability */ - xi.type = IPFW_TABLE_CIDR; - xi.vtype = IPFW_VTYPE_U32; - while (ac > 0) { if ((tcmd = match_token(tablenewcmds, *av)) == -1) errx(EX_USAGE, "unknown option: %s", *av); @@ -542,6 +549,25 @@ table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i) return (error); } + +/* + * Locks or unlocks given table + */ +static void +table_lock(ipfw_obj_header *oh, int lock) +{ + ipfw_xtable_info xi; + int error; + + memset(&xi, 0, sizeof(xi)); + + xi.mflags |= IPFW_TMFLAGS_LOCK; + xi.flags |= (lock != 0) ? IPFW_TGFLAGS_LOCKED : 0; + + if ((error = table_do_modify(oh, &xi)) != 0) + err(EX_OSERR, "Table %s failed", lock != 0 ? "lock" : "unlock"); +} + /* * Destroys given table specified by @oh->ntlv. * Returns 0 on success. @@ -713,7 +739,10 @@ table_show_info(ipfw_xtable_info *i, void *arg) snprintf(tvtype, sizeof(tvtype), "%s", vtype); printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); - printf(" kindex: %d, type: %s\n", i->kidx, ttype); + if ((i->flags & IPFW_TGFLAGS_LOCKED) != 0) + printf(" kindex: %d, type: %s, locked\n", i->kidx, ttype); + else + printf(" kindex: %d, type: %s\n", i->kidx, ttype); printf(" valtype: %s, references: %u\n", tvtype, i->refcnt); printf(" algorithm: %s\n", i->algoname); printf(" items: %u, size: %u\n", i->count, i->size); @@ -1007,6 +1036,9 @@ table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, case ENOENT: etxt = "record not found"; break; + case EACCES: + etxt = "table is locked"; + break; default: etxt = strerror(error); } diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index da09c13a1490..4d6c3baf5f85 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -866,7 +866,7 @@ typedef struct _ipfw_xtable_info { uint8_t vtype; /* value type (u32) */ uint8_t vftype; /* value format type (ip,number)*/ uint16_t mflags; /* modification flags */ - uint16_t spare; + uint16_t flags; /* generic table flags */ uint32_t set; /* set table is in */ uint32_t kidx; /* kernel index */ uint32_t refcnt; /* number of references */ @@ -877,13 +877,18 @@ typedef struct _ipfw_xtable_info { char algoname[64]; /* algorithm name */ ipfw_ta_tinfo ta_info; /* additional algo stats */ } ipfw_xtable_info; +/* Generic table flags */ +#define IPFW_TGFLAGS_LOCKED 0x01 /* Tables is locked from changes*/ +/* Table type-specific flags */ #define IPFW_TFFLAG_SRCIP 0x01 #define IPFW_TFFLAG_DSTIP 0x02 #define IPFW_TFFLAG_SRCPORT 0x04 #define IPFW_TFFLAG_DSTPORT 0x08 #define IPFW_TFFLAG_PROTO 0x10 -#define IPFW_TMFLAGS_FTYPE 0x01 /* Change ftype field */ -#define IPFW_TMFLAGS_LIMIT 0x02 /* Change limit value */ +/* Table modification flags */ +#define IPFW_TMFLAGS_FTYPE 0x0001 /* Change ftype field */ +#define IPFW_TMFLAGS_LIMIT 0x0002 /* Change limit value */ +#define IPFW_TMFLAGS_LOCK 0x0004 /* Change table lock state */ typedef struct _ipfw_iface_info { char ifname[64]; /* interface name */ diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c index 596437535b18..a795a04e123a 100644 --- a/sys/netpfil/ipfw/ip_fw_table.c +++ b/sys/netpfil/ipfw/ip_fw_table.c @@ -76,7 +76,7 @@ struct table_config { uint8_t vtype; /* value type */ uint8_t vftype; /* value format type */ uint8_t tflags; /* type flags */ - uint8_t spare0; + uint8_t locked; /* 1 if locked from changes */ uint32_t count; /* Number of records */ uint32_t limit; /* Max number of records */ uint8_t linked; /* 1 if already linked */ @@ -210,6 +210,11 @@ add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, return (EINVAL); } + if (tc->locked != 0) { + IPFW_UH_WUNLOCK(ch); + return (EACCES); + } + /* Try to exit early on limit hit */ if ((error = check_table_limit(tc, tei)) != 0 && count == 1) { IPFW_UH_WUNLOCK(ch); @@ -439,6 +444,11 @@ del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, return (ESRCH); } + if (tc->locked != 0) { + IPFW_UH_WUNLOCK(ch); + return (EACCES); + } + if (tc->no.type != ti->type) { IPFW_UH_WUNLOCK(ch); return (EINVAL); @@ -1616,6 +1626,8 @@ ipfw_modify_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, tc->vftype = i->vftype; if ((i->mflags & IPFW_TMFLAGS_LIMIT) != 0) tc->limit = i->limit; + if ((i->mflags & IPFW_TMFLAGS_LOCK) != 0) + tc->locked = ((i->flags & IPFW_TGFLAGS_LOCKED) != 0); IPFW_UH_WUNLOCK(ch); return (0); @@ -1704,6 +1716,7 @@ create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti, tc->vftype = i->vftype; tc->limit = i->limit; + tc->locked = (i->flags & IPFW_TGFLAGS_LOCKED) != 0; IPFW_UH_WLOCK(ch); @@ -1792,6 +1805,7 @@ export_table_info(struct ip_fw_chain *ch, struct table_config *tc, i->refcnt = tc->no.refcnt; i->count = tc->count; i->limit = tc->limit; + i->flags |= (tc->locked != 0) ? IPFW_TGFLAGS_LOCKED : 0; i->size = tc->count * sizeof(ipfw_obj_tentry); i->size += sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info); strlcpy(i->tablename, tc->tablename, sizeof(i->tablename));