From: marta Date: Mon, 16 Nov 2009 22:19:32 +0000 (+0000) Subject: Major changes: X-Git-Tag: ipfw-0.9-6~5 X-Git-Url: http://git.onelab.eu/?p=ipfw.git;a=commitdiff_plain;h=6c2e192c3237bd46db6ad4230fed71d28f362331 Major changes: On the kernel side: removed goto from the main ipfw_chk() switch, splitted the static and dynamic rules requests, added O_JAIL and O_GID match. On userland: use the reentrant qsort_r() instead of the heapsort() function, splitted the static and dynamic rules requests. Minor changes: removed debug messages, added comments, sync with the linux version. --- diff --git a/Makefile b/Makefile index a35b722..2410b3d 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,15 @@ # $Id$ +# # Top level makefile for building ipfw kernel and userspace. # You can run it manually or also under the Planetlab build. # Planetlab wants also the 'install' target. +# +# To build on system with non standard Kernel sources or userland files, +# you should run this with +# +# make KERNELPATH=/path/to/linux-2.x.y.z USRDIR=/path/to/usr +# +# We assume that $(USRDIR) contains include/ and lib/ used to build userland. DATE ?= $(shell date +%Y%m%d) SNAPSHOT_NAME=ipfw_linux-$(DATE) diff --git a/README b/README index fd40bac..fe5c578 100644 --- a/README +++ b/README @@ -74,14 +74,14 @@ Unless specified otherwise, all the code here is under a BSD license. - fetch and extract the code e.g. (cd ..; \ - wget http://info.iet.unipi.it/~luigi/dummynet/ipfw_linux-20090622.tgz;\ - tar xvzf ipfw_linux-20090622.tgz) + wget http://info.iet.unipi.it/~luigi/dummynet/ipfw_linux-20090724.tgz;\ + tar xvzf ipfw_linux-20090724.tgz; mv ipfw_linux-20090724 ipfw_mod;) (but you should have done it already) - run the following commands: - (mkdir packages/ipfw2; - cp ../ipfw_mod/Makefile.openwrt packages/ipfw2/Makefile) + (mkdir package/ipfw2; + cp ../ipfw_linux/Makefile.openwrt package/ipfw2/Makefile) to create the package/ipfw2 directory in the OpenWrt source directory, and copy Makefile.openwrt to package/ipfw2/Makefile: diff --git a/dummynet/include/sys/malloc.h b/dummynet/include/sys/malloc.h index 03b9dfb..b6c4ac5 100644 --- a/dummynet/include/sys/malloc.h +++ b/dummynet/include/sys/malloc.h @@ -8,9 +8,21 @@ */ #ifndef _WIN32 /* this is the linux version */ +/* + * XXX On zeroshell (2.6.25.17) we get a load error + * __you_cannot_kmalloc_that_much + * which is triggered when kmalloc() is called with a large + * compile-time constant argument (include/linux/slab_def.h) + * + * I think it may be a compiler (or source) bug because there is no + * evidence that such a large request is made. + * Making the _size argument to kmalloc volatile prevents the compiler + * from making the mistake, though it is clearly not ideal. + */ + #if !defined (LINUX_24) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) #define malloc(_size, type, flags) \ - kmalloc(_size, GFP_ATOMIC | __GFP_ZERO) + ({ volatile int _v = _size; kmalloc(_v, GFP_ATOMIC | __GFP_ZERO); }) #else /* LINUX <= 2.6.22 and LINUX_24 */ /* linux 2.6.22 does not zero allocated memory */ #define malloc(_size, type, flags) \ diff --git a/dummynet/ip_dummynet.c b/dummynet/ip_dummynet.c index b8cbc2e..c0399bb 100644 --- a/dummynet/ip_dummynet.c +++ b/dummynet/ip_dummynet.c @@ -1549,9 +1549,15 @@ dropit: * Below, the rt_unref is only needed when (pkt->dn_dir == DN_TO_IP_OUT) * Doing this would probably save us the initial bzero of dn_pkt */ +#if defined( __linux__ ) +#define DN_FREE_PKT(_m) do { \ + netisr_dispatch(-1, _m); \ +} while (0) +#else #define DN_FREE_PKT(_m) do { \ m_freem(_m); \ } while (0) +#endif /* * Dispose all packets and flow_queues on a flow_set. diff --git a/dummynet/ip_fw2.c b/dummynet/ip_fw2.c index e3483df..4c9b0a3 100644 --- a/dummynet/ip_fw2.c +++ b/dummynet/ip_fw2.c @@ -2002,25 +2002,6 @@ check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif, int match = 0; struct sk_buff *skb = ((struct mbuf *)inp)->m_skb; -#if 0 /* debug */ - printf("%s opcode %d arg %d oif %p src 0x%x:%d dst 0x%x:%d\n", __FUNCTION__, - insn->o.opcode, insn->d[0], oif, - ntohl(src_ip.s_addr), ntohs(src_port), - ntohl(dst_ip.s_addr), ntohs(dst_port) - ); -#endif - if (insn->o.opcode == O_JAIL) { -#ifdef IPFW_PLANETLAB - match = (skb->skb_tag == insn->d[0]); -#if 0 /* debug */ - printf("JAIL compiled for planetlab xid %d want %d result %d\n", - skb->skb_tag, insn->d[0], match); -#endif - -#endif - return match; - } - if (*ugid_lookupp == 0) { /* actively lookup and copy in cache */ /* returns null if any element of the chain up to file is null. @@ -2037,6 +2018,11 @@ check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif, if (insn->o.opcode == O_UID) match = (ugp->fw_uid == (uid_t)insn->d[0]); + else if (insn->o.opcode == O_JAIL) + match = (ugp->fw_groups[1] == (uid_t)insn->d[0]); + else if (insn->o.opcode == O_GID) + match = (ugp->fw_groups[0] == (uid_t)insn->d[0]); + return match; #else /* FreeBSD */ @@ -2273,6 +2259,8 @@ ipfw_chk(struct ip_fw_args *args) /* end of ipv6 variables */ int is_ipv4 = 0; + int done = 0; /* flag for actions match */ + if (m->m_flags & M_SKIP_FIREWALL) return (IP_FW_PASS); /* accept */ @@ -2583,7 +2571,7 @@ do { \ uint32_t tablearg = 0; int l, cmdlen, skip_or; /* skip rest of OR block */ -again: +/* again: */ if (set_disable & (1 << f->set) ) continue; @@ -2598,7 +2586,7 @@ again: * the target rule. */ -check_body: +/* check_body: */ cmdlen = F_LEN(cmd); /* * An OR block (insn_1 || .. || insn_n) has the @@ -3178,8 +3166,8 @@ check_body: * Exceptions: * O_COUNT and O_SKIPTO actions: * instead of terminating, we jump to the next rule - * ('goto next_rule', equivalent to a 'break 2'), - * or to the SKIPTO target ('goto again' after + * ('break' after setting match and l) + * or to the SKIPTO target ('break' after * having set f, cmd and l), respectively. * * O_TAG, O_LOG and O_ALTQ action parameters: @@ -3197,19 +3185,24 @@ check_body: * O_PROBE_STATE and O_CHECK_STATE: these opcodes * cause a lookup of the state table, and a jump * to the 'action' part of the parent rule - * ('goto check_body') if an entry is found, or + * if an entry is found, or * (CHECK_STATE only) a jump to the next rule if * the entry is not found ('goto next_rule'). * The result of the lookup is cached to make * further instances of these opcodes are * effectively NOPs. + * The jump to the next rule is done by a break + * after zeroing the cmdlen value and setting + * match. */ case O_LIMIT: case O_KEEP_STATE: if (install_state(f, (ipfw_insn_limit *)cmd, args, tablearg)) { retval = IP_FW_DENY; - goto done; /* error/limit violation */ + /* was goto done; */ /* error/limit violation */ + l = 0; /* break the inner loop */ + done = 1; /* break the external loop */ } match = 1; break; @@ -3241,7 +3234,10 @@ check_body: cmd = ACTION_PTR(f); l = f->cmd_len - f->act_ofs; IPFW_DYN_UNLOCK(); - goto check_body; + /* previously was goto check_body; */ + cmdlen = 0; /* make null for() changes */ + match = 1; /* do not break to the external loop */ + break; } /* * Dynamic entry not found. If CHECK_STATE, @@ -3249,13 +3245,16 @@ check_body: * ignore and continue with next opcode. */ if (cmd->opcode == O_CHECK_STATE) - goto next_rule; + l = 0; /* was goto next_rule; */ match = 1; break; case O_ACCEPT: retval = 0; /* accept */ - goto done; + /* was goto done; */ + l = 0; /* break the inner loop */ + done = 1; /* break the external loop */ + break; case O_PIPE: case O_QUEUE: @@ -3265,7 +3264,10 @@ check_body: else args->cookie = cmd->arg1; retval = IP_FW_DUMMYNET; - goto done; + /* was goto done; */ + l = 0; /* break the inner loop */ + done = 1; /* break the external loop */ + break; #if 0 case O_DIVERT: @@ -3292,7 +3294,10 @@ check_body: m_tag_prepend(m, mtag); retval = (cmd->opcode == O_DIVERT) ? IP_FW_DIVERT : IP_FW_TEE; - goto done; + /* was goto done; */ + l = 0; /* break the inner loop */ + done = 1; /* break the external loop */ + break; } #endif @@ -3301,8 +3306,12 @@ check_body: f->pcnt++; /* update stats */ f->bcnt += pktlen; f->timestamp = time_uptime; - if (cmd->opcode == O_COUNT) - goto next_rule; + if (cmd->opcode == O_COUNT) { + /* was goto next_rule; */ + l = 0; /* exit the inner loop */ + match = 1; /* do not break the loop */ + break; + } /* handle skipto */ if (cmd->arg1 == IP_FW_TABLEARG) { f = lookup_next_rule(f, tablearg); @@ -3311,7 +3320,26 @@ check_body: lookup_next_rule(f, 0); f = f->next_rule; } - goto again; + /* previously was "goto again;" + * We emulate by re-entering the inner loop + * with the correct f, l and cmd. + * First, skip over disabled rules. + * Should at least match the default rule, + * but try to be robust. + */ + while (f && (set_disable & (1 << f->set))) + f = f->next; + /* prepare to re-enter the inner loop. */ + if (f) { /* better safe than sorry */ + l = f->cmd_len; + cmd = f->cmd; + } else { + l = 0; /* this will break the inner loop */ + } + cmdlen = 0; /* reset loop condition */ + skip_or = 0; + match = 1; /* do not break the loop */ + break; case O_REJECT: /* @@ -3345,7 +3373,10 @@ check_body: #endif case O_DENY: retval = IP_FW_DENY; - goto done; + /* goto done; */ + l = 0; /* break the inner loop */ + done = 1; /* break the external loop */ + break; case O_FORWARD_IP: { struct sockaddr_in *sa; @@ -3366,7 +3397,10 @@ check_body: } retval = IP_FW_PASS; } - goto done; + /* goto done; */ + l = 0; /* break the inner loop */ + done = 1; /* break the external loop */ + break; case O_NETGRAPH: case O_NGTEE: @@ -3377,7 +3411,10 @@ check_body: args->cookie = cmd->arg1; retval = (cmd->opcode == O_NETGRAPH) ? IP_FW_NETGRAPH : IP_FW_NGTEE; - goto done; + /* goto done; */ + l = 0; /* break the inner loop */ + done = 1; /* break the external loop */ + break; #if 0 case O_SETFIB: @@ -3386,7 +3423,10 @@ check_body: f->timestamp = time_uptime; M_SETFIB(m, cmd->arg1); args->f_id.fib = cmd->arg1; - goto next_rule; + /* was goto next_rule; */ + l = 0; + match = 1; + break; case O_NAT: { struct cfg_nat *t; @@ -3401,7 +3441,10 @@ check_body: LOOKUP_NAT(layer3_chain, nat_id, t); if (t == NULL) { retval = IP_FW_DENY; - goto done; + /* goto done; */ + l = 0; /* break the inner loop */ + done = 1; /* break the external loop */ + break; } if (cmd->arg1 != IP_FW_TABLEARG) ((ipfw_insn_nat *)cmd)->nat = t; @@ -3409,7 +3452,10 @@ check_body: retval = ipfw_nat_ptr(args, t, m); } else retval = IP_FW_DENY; - goto done; + /* goto done; */ + l = 0; /* break the inner loop */ + done = 1; /* break the external loop */ + break; } #endif @@ -3431,21 +3477,25 @@ check_body: } /* end of inner for, scan opcodes */ -next_rule:; /* try next rule */ + if (done) + break; +/* next_rule:; */ /* try next rule */ } /* end of outer for, scan rules */ + + if (done) { + /* Update statistics */ + f->pcnt++; + f->bcnt += pktlen; + f->timestamp = time_uptime; + IPFW_RUNLOCK(chain); + return (retval); + } + printf("ipfw: ouch!, skip past end of rules, denying packet\n"); IPFW_RUNLOCK(chain); return (IP_FW_DENY); -done: - /* Update statistics */ - f->pcnt++; - f->bcnt += pktlen; - f->timestamp = time_uptime; - IPFW_RUNLOCK(chain); - return (retval); - pullup_failed: if (fw_verbose) printf("ipfw: pullup failed\n"); @@ -4147,7 +4197,7 @@ bad_size: } /* - * Copy the static and dynamic rules to the supplied buffer + * Copy the static rules to the supplied buffer * and return the amount of space actually used. */ static size_t @@ -4160,6 +4210,7 @@ ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space) time_t boot_seconds; boot_seconds = boottime.tv_sec; + /* XXX this can take a long time and locking will block packet flow */ IPFW_RLOCK(chain); for (rule = chain->rules; rule ; rule = rule->next) { @@ -4185,6 +4236,27 @@ ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space) } } IPFW_RUNLOCK(chain); + + return (bp - (char *)buf); +} + +/* + * Copy the dynamic rules to the supplied buffer + * and return the amount of space actually used. + * XXX marta if we allocate X and rules grows + * we check for size limit while copying rules into the buffer + */ +static size_t +ipfw_getdynrules(struct ip_fw_chain *chain, void *buf, size_t space) +{ + char *bp = buf; + char *ep = bp + space; + int i; + time_t boot_seconds; + + printf("dynrules requested\n"); + boot_seconds = boottime.tv_sec; + if (ipfw_dyn_v) { ipfw_dyn_rule *p, *last = NULL; @@ -4217,12 +4289,16 @@ ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space) TIME_LEQ(dst->expire, time_uptime) ? 0 : dst->expire - time_uptime ; bp += sizeof(ipfw_dyn_rule); + } else { + p = NULL; /* break the loop */ + i = curr_dyn_buckets; } } IPFW_DYN_UNLOCK(); if (last != NULL) /* mark last dynamic rule */ bzero(&last->next, sizeof(last)); } + return (bp - (char *)buf); } @@ -4259,10 +4335,8 @@ ipfw_ctl(struct sockopt *sopt) switch (sopt->sopt_name) { case IP_FW_GET: /* - * pass up a copy of the current rules. Static rules - * come first (the last of which has number IPFW_DEFAULT_RULE), - * followed by a possibly empty list of dynamic rule. - * The last dynamic rule has NULL in the "next" field. + * pass up a copy of the current static rules. + * The last static rule has number IPFW_DEFAULT_RULE. * * Note that the calculated size is used to bound the * amount of data returned to the user. The rule set may @@ -4270,8 +4344,6 @@ ipfw_ctl(struct sockopt *sopt) * data in which case we'll just return what fits. */ size = static_len; /* size of static rules */ - if (ipfw_dyn_v) /* add size of dyn.rules */ - size += (dyn_count * sizeof(ipfw_dyn_rule)); /* * XXX todo: if the user passes a short length just to know @@ -4284,6 +4356,20 @@ ipfw_ctl(struct sockopt *sopt) free(buf, M_TEMP); break; + case IP_FW_DYN_GET: + /* + * pass up a copy of the current dynamic rules. + * The last dynamic rule has NULL in the "next" field. + */ + /* if (!ipfw_dyn_v) XXX check for empty set ? */ + size = (dyn_count * sizeof(ipfw_dyn_rule)); /* size of dyn. rules */ + + buf = malloc(size, M_TEMP, M_WAITOK); + error = sooptcopyout(sopt, buf, + ipfw_getdynrules(&layer3_chain, buf, size)); + free(buf, M_TEMP); + break; + case IP_FW_FLUSH: /* * Normally we cannot release the lock on each iteration. diff --git a/dummynet/ipfw2_mod.c b/dummynet/ipfw2_mod.c index 3bf836a..b072ab5 100644 --- a/dummynet/ipfw2_mod.c +++ b/dummynet/ipfw2_mod.c @@ -282,13 +282,14 @@ static struct nf_sockopt_ops ipfw_sockopts = { #endif /* - * ipfw hooks the POST_ROUTING and the PRE_ROUTING chain. - * PlanetLab tags the xid in the LOCAL_INPUT and in the - * POST_ROUTING chain, so if we want to intercept the - * traffic by using the id we need to hook the LOCAL_INPUT - * chain instead of the PRE_ROUTING. + * ipfw hooks into the POST_ROUTING and the PRE_ROUTING chains. + * PlanetLab sets skb_tag to the slice id in the LOCAL_INPUT and + * POST_ROUTING chains, so if we want to use that information we + * need to hook the LOCAL_INPUT chain instead of the PRE_ROUTING. + * However at the moment the skb_tag info is not reliable so + * we stay with the standard hooks. */ -#ifdef IPFW_PLANETLAB +#if 0 // defined(IPFW_PLANETLAB) #define IPFW_HOOK_IN NF_IP_LOCAL_IN #else #define IPFW_HOOK_IN NF_IP_PRE_ROUTING @@ -461,8 +462,24 @@ ip_output(struct mbuf *m, struct mbuf __unused *opt, * * We do this only on selected protocols: TCP, ... * - * Note- for locally generated, outgoing packets we don't need to - * do a lookup because the sk_buff already points to the socket where + * The chain is the following + * sk_buff* sock* socket* file* + * skb -> sk ->sk_socket->file ->f_owner ->pid + * skb -> sk ->sk_socket->file ->f_uid (direct) + * skb -> sk ->sk_socket->file ->f_cred->fsuid (2.6.29+) + * + * Related headers: + * linux/skbuff.h struct skbuff + * net/sock.h struct sock + * linux/net.h struct socket + * linux/fs.h struct file + * + * With vserver we may have sk->sk_xid and sk->sk_nid that + * which we store in fw_groups[1] (matches O_JAIL) and fw_groups[2] + * (no matches yet) + * + * Note- for locally generated, outgoing packets we should not need + * need a lookup because the sk_buff already points to the socket where * the info is. */ extern struct inet_hashinfo tcp_hashinfo; @@ -491,10 +508,18 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport, */ #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24) #define _OPT_NET_ARG -#else /* 2.6.25 and above */ +#else +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) +/* there is no dev_net() on 2.6.25 */ +#define _OPT_NET_ARG (skb->dev->nd_net), +#else /* 2.6.26 and above */ #define _OPT_NET_ARG dev_net(skb->dev), +#endif #endif + if (0 && skb->sk) { + sk=skb->sk; + } else { sk = (dir) ? inet_lookup(_OPT_NET_ARG &tcp_hashinfo, daddr, dport, saddr, sport, // matches outgoing for server sockets @@ -502,6 +527,7 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport, inet_lookup(_OPT_NET_ARG &tcp_hashinfo, saddr, sport, daddr, dport, // matches incoming for server sockets skb->dev->ifindex); + } #undef _OPT_NET_ARG /* no match, nothing to be done */ @@ -534,9 +560,15 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport, sk->sk_socket && sk->sk_socket->file) { ugp->fw_uid = sk->sk_socket->file->_CURR_UID; uid = ugp->fw_uid; + ugp->fw_groups[0] = sk->sk_socket->file->_CURR_GID; +#ifdef CONFIG_VSERVER + ugp->fw_groups[1] = sk->sk_xid; + ugp->fw_groups[2] = sk->sk_nid; +#endif ret = 1; } - sock_put(sk); + if (1 && !skb->sk) /* the reference came from the lookup */ + sock_put(sk); #undef _CURR_UID #undef _CURR_GID diff --git a/dummynet/missing.h b/dummynet/missing.h index c47b117..b15d84a 100644 --- a/dummynet/missing.h +++ b/dummynet/missing.h @@ -25,6 +25,7 @@ /* * $Id$ + * * Header for kernel variables and functions that are not available in * userland. */ diff --git a/glue.h b/glue.h index ff7ef07..86b229a 100644 --- a/glue.h +++ b/glue.h @@ -23,7 +23,6 @@ * SUCH DAMAGE. */ /* - * * $Id$ * * glue code to adapt the FreeBSD version to linux and windows, @@ -213,7 +212,6 @@ struct clockinfo { void qsort_r(void *a, size_t n, size_t es, void *thunk, int cmp_t(void *, const void *, const void *)); -#define heapsort(_a, _b, _c, _d) qsort(_a, _b, _c, _d) #define setprogname(x) /* not present in linux */ diff --git a/ipfw/Makefile b/ipfw/Makefile index a8a4f47..bcaed9c 100644 --- a/ipfw/Makefile +++ b/ipfw/Makefile @@ -6,12 +6,10 @@ # enable extra debugging information # Do not set with = or := so we can inherit from the caller $(warning Building userland ipfw for $(VER)) -EXTRA_CFLAGS += EXTRA_CFLAGS += -O1 +# comment this on planetlab +# EXTRA_CFLAGS += -Wall -Werror EXTRA_CFLAGS += -include ../glue.h - -LDFLAGS= - EXTRA_CFLAGS += -I ./include ifneq ($(VER),openwrt) @@ -25,8 +23,12 @@ endif endif # !openwrt CFLAGS += $(EXTRA_CFLAGS) +# Location of OS headers and libraries. After our stuff. +USRDIR?= /usr +CFLAGS += -I$(USRDIR)/include +LDFLAGS += -L$(USRDIR)/lib -OBJS = ipfw2.o dummynet.o main.o ipv6.o altq.o +OBJS = ipfw2.o dummynet.o main.o ipv6.o altq.o qsort_r.o ifneq ($(HAVE_NAT),) OBJS += nat.o EXTRA_CFLAGS += -DHAVE_NAT diff --git a/ipfw/add_rules b/ipfw/add_rules index 1f90c75..f7866d7 100755 --- a/ipfw/add_rules +++ b/ipfw/add_rules @@ -1,4 +1,6 @@ #!/bin/bash +# +# A test script to add rules PRG=./ipfw diff --git a/ipfw/dummynet.c b/ipfw/dummynet.c index fd8fc4d..e2c5ff1 100644 --- a/ipfw/dummynet.c +++ b/ipfw/dummynet.c @@ -74,8 +74,12 @@ static struct _s_x dummynet_params[] = { { NULL, 0 } /* terminator */ }; +/* + * XXX to be updated to the new version, + * without the global struct command_opts variable + */ static int -sort_q(const void *pa, const void *pb) +sort_q(void * to_be_done, const void *pa, const void *pb) { int rev = (co.do_sort < 0); int field = rev ? -co.do_sort : co.do_sort; @@ -118,7 +122,7 @@ list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q) return; if (co.do_sort != 0) - heapsort(q, fs->rq_elements, sizeof *q, sort_q); + qsort_r(q, fs->rq_elements, sizeof *q, NULL, sort_q); /* Print IPv4 flows */ index_printed = 0; @@ -477,7 +481,7 @@ is_valid_number(const char *s) * and return the numeric bandwidth value. * set clocking interface or bandwidth value */ -void +static void read_bandwidth(char *arg, int *bandwidth, char *if_name, int namelen) { if (*bandwidth != -1) @@ -521,7 +525,7 @@ struct point { double delay; }; -int +static int compare_points(const void *vp1, const void *vp2) { const struct point *p1 = vp1; diff --git a/ipfw/ipfw2.c b/ipfw/ipfw2.c index ed12d9c..8d6ed87 100644 --- a/ipfw/ipfw2.c +++ b/ipfw/ipfw2.c @@ -358,7 +358,8 @@ do_cmd(int optname, void *optval, uintptr_t optlen) if (s < 0) err(EX_UNAVAILABLE, "socket"); - if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET || + if (optname == IP_FW_GET || optname == IP_FW_DYN_GET || + optname == IP_DUMMYNET_GET || optname == IP_FW_ADD || optname == IP_FW_TABLE_LIST || optname == IP_FW_TABLE_GETSIZE || optname == IP_FW_NAT_GET_CONFIG || @@ -1719,12 +1720,14 @@ void ipfw_list(int ac, char *av[], int show_counters) { struct ip_fw *r; - ipfw_dyn_rule *dynrules, *d; + ipfw_dyn_rule *dynrules = NULL; + ipfw_dyn_rule *d; #define NEXT(r) ((struct ip_fw *)((char *)r + RULESIZE(r))) char *lim; void *data = NULL; - int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width; + int bcwidth, n, nbytes, pcwidth, width, nstat; + int ndyn = 0; int exitval = EX_OK; int lac; char **lav; @@ -1732,8 +1735,13 @@ ipfw_list(int ac, char *av[], int show_counters) char *endptr; int seen = 0; uint8_t set; + int ocmd = IP_FW_GET; + + if (co.do_pipe) + ocmd = IP_DUMMYNET_GET; + else if (co.do_dynamic) + ocmd = IP_FW_DYN_GET; - const int ocmd = co.do_pipe ? IP_DUMMYNET_GET : IP_FW_GET; int nalloc = 1024; /* start somewhere... */ last = 0; @@ -1767,19 +1775,25 @@ ipfw_list(int ac, char *av[], int show_counters) * Count static rules. They have variable size so we * need to scan the list to count them. */ + nstat = 0; + r = data; + + if (!co.do_dynamic) { for (nstat = 1, r = data, lim = (char *)data + nbytes; r->rulenum < IPFW_DEFAULT_RULE && (char *)r < lim; ++nstat, r = NEXT(r) ) ; /* nothing */ + } /* * Count dynamic rules. This is easier as they have * fixed size. */ - r = NEXT(r); - dynrules = (ipfw_dyn_rule *)r ; - n = (char *)r - (char *)data; - ndyn = (nbytes - n) / sizeof *dynrules; + if (co.do_dynamic) { + dynrules = (ipfw_dyn_rule *)r ; + n = (char *)r - (char *)data; + ndyn = (nbytes - n) / sizeof *dynrules; + } /* if showing stats, figure out column widths ahead of time */ bcwidth = pcwidth = 0; @@ -1802,6 +1816,7 @@ ipfw_list(int ac, char *av[], int show_counters) bcwidth = width; } } + if (co.do_dynamic && ndyn) { for (n = 0, d = dynrules; n < ndyn; n++, d++) { if (co.use_set) { @@ -1822,6 +1837,7 @@ ipfw_list(int ac, char *av[], int show_counters) bcwidth = width; } } + /* if no rule numbers were specified, list all rules */ if (ac == 0) { for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) { @@ -1847,6 +1863,7 @@ ipfw_list(int ac, char *av[], int show_counters) /* display specific rules requested on command line */ + if (!co.do_dynamic) { for (lac = ac, lav = av; lac != 0; lac--) { /* convert command line rule # */ last = rnum = strtoul(*lav++, &endptr, 10); @@ -1874,6 +1891,7 @@ ipfw_list(int ac, char *av[], int show_counters) warnx("rule %lu does not exist", rnum); } } + } if (co.do_dynamic && ndyn) { printf("## Dynamic rules:\n"); diff --git a/slice/netconfig b/slice/netconfig index efad8e7..e2afb0a 100755 --- a/slice/netconfig +++ b/slice/netconfig @@ -1,145 +1,14 @@ #!/bin/sh # -# Marta Carbone +# Marta Carbone, Luigi Rizzo # Copyright (C) 2009 Universita` di Pisa # $Id$ # -# This script is the frontend to be used with -# the vsys system. -# It allows to configure dummynet pipes and queues. -# In detail it: -# - get user input -# - send command to the vsys input pipe -# - wait a bit -# - get the reply from the output vsys pipe -# - show the output to the user -# -# A simple usage is: -# ./netconfig -p 9898 -# mandatory fields are the port to be configured -# and dummynet configuration parameters +# This script is the frontend to be used with the vsys system. +# It simply passes information to the backend and gets back the reply PIPE_IN=/vsys/ipfw-be.in PIPE_OUT=/vsys/ipfw-be.out -LOGFILE=/tmp/netconfig.log -SED=/bin/sed # used to extract the profile name -DEBUG=0 # 0 disable debug messages -prog=$0 # this program - -# Print the first argument and exit -abort() -{ - echo "$1"; exit 1 -} - -# if $DEBUG is enabled, print a debug message -# $1 the message to print -debug() -{ - [ "${DEBUG}" != "0" ] && echo "$1" >> ${LOGFILE} -} - -# print the usage and exit -help() -{ - cat << EOF -Usage: $prog -p port [-U] [-t timeout[STRING]] ipfw_configuration_parameters \n - $prog ipfw show \n - $prog pipe show \n - - -h show help \n - -p specify the port to configure \n - -d delete specified rules and pipes \n - -t specify the timeout. STRING can be "1minute" or "4hours" (default 1 hour) \n - - ipfw configuration parameters (mandatory) \n - extra-delay bw delay proto... plr... \n - - ipfw show show the ipfw ruleset - ipfw pipe show the configured pipes -EOF - exit 0 -} - -# parse input line and fill missing fields -parse_input() -{ - # counters used to check if at least - # two ipfw configuration parameters are present - local OPT_ARGS=2 # optional (timeout) - local MAND_ARGS=2 # mandatory (port) - - [ -z "$1" ] && help; - - while getopts ":hdp:t:" opt; do - case $opt in - h | \?) help;; - p) PORT=$OPTARG;; - d) DELETE=1;; - t) TIMEOUT=$OPTARG;; - esac - done - - # check for mandatory arguments - [ -z ${PORT} ] && abort "a port value is mandatory"; - - # the default value for the timeout is 1H - if [ -z ${TIMEOUT} ]; then - TIMEOUT="1hour" - OPT_ARGS=$((${OPT_ARGS}-2)) - fi - - # check for deletion flag - if [ -z ${DELETE} ]; then - DELETE=0 - else - # if d is present configuration is not required - MAND_ARGS=$((${MAND_ARGS}-2)) - fi - - # compute residue argument, we need at least 2 - # mandatory arguments (for ipfw), exit on error - # debug "Passed args $# Mandatory ${MAND_ARGS} Optional ${OPT_ARGS} Extra $(($#-${MAND_ARGS}-${OPT_ARGS}))" - if [ $(($#-${MAND_ARGS}-${OPT_ARGS})) -lt 2 ]; then - help - fi -} - -# the backend expects lines in the format: -# ipfw -# pipe -# port timeout configuration_string -# main starts here - - # allow ipfw show and ipfw pipe show commands - if [ x$1 = x"ipfw" ]; then - echo "received" $1 - echo "ipfw" >> ${PIPE_IN} - cat ${PIPE_OUT} - exit 0; - else if [ x$1 = x"pipe" ]; then - echo "pipe" >> ${PIPE_IN} - cat ${PIPE_OUT} - exit 0; - fi - fi - - # parse the input - parse_input $* - shift $((${OPTIND}-1)); - - # print debug - debug "PORT ${PORT}" - debug "DELETE ${DELETE}" - debug "TIMEOUT ${TIMEOUT}" - debug "PIPE_CONFIGURATION $*" - - # format CMD as expected by the backend script - CMD="${PORT} ${TIMEOUT} ${DELETE} $*"; - - # send the command - debug "Sending: ${CMD}" - echo ${CMD} >> ${PIPE_IN} - - cat ${PIPE_OUT} +sudo sh -c "echo $* >> ${PIPE_IN}" +sudo sh -c "cat ${PIPE_OUT}"