X-Git-Url: http://git.onelab.eu/?p=ipfw.git;a=blobdiff_plain;f=dummynet%2Fip_fw2.c;h=4c9b0a38d48312ad9713e7bd900ef2fa8a5360b7;hp=e3483dfae1d69e8792c40772df5bbfe51b69d20e;hb=6c2e192c3237bd46db6ad4230fed71d28f362331;hpb=b933933b5c82d840de435395dfbb5558cabd66d0 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.