X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=dummynet%2Fip_fw2.c;h=d05fa7473d3548b00e7e38e4b0f2bbe902d253f7;hb=1f3693d89c1c88e895721e21751c354e74b99627;hp=4e8961db83abf0c1bac1644469aa760e429ae020;hpb=830ae69210540ea0e1ba3cc5d0db954b7107fbcc;p=ipfw.git diff --git a/dummynet/ip_fw2.c b/dummynet/ip_fw2.c index 4e8961d..d05fa74 100644 --- a/dummynet/ip_fw2.c +++ b/dummynet/ip_fw2.c @@ -1978,7 +1978,7 @@ dump_table(struct ip_fw_chain *ch, ipfw_table *tbl) } #endif -#if 0 +#ifndef linux /* FreeBSD */ static void fill_ugid_cache(struct inpcb *inp, struct ip_fw_ugid *ugp) { @@ -1990,51 +1990,43 @@ fill_ugid_cache(struct inpcb *inp, struct ip_fw_ugid *ugp) ugp->fw_ngroups = cr->cr_ngroups; bcopy(cr->cr_groups, ugp->fw_groups, sizeof(ugp->fw_groups)); } -#endif /* no uigid support */ +#endif static int check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif, struct in_addr dst_ip, u_int16_t dst_port, struct in_addr src_ip, u_int16_t src_port, struct ip_fw_ugid *ugp, int *ugid_lookupp, - struct inpcb *inp, struct sk_buff *skb) + struct inpcb *inp) { -#if 1 /* Linux */ +#ifdef linux + int match = 0; + struct sk_buff *skb = ((struct mbuf *)inp)->m_skb; - const struct file *filp; + if (*ugid_lookupp == 0) { /* actively lookup and copy in cache */ - if (insn->o.opcode == O_JAIL) - return 0; - - if (skb->sk == NULL || skb->sk->sk_socket == NULL) - return 0; + /* returns null if any element of the chain up to file is null. + * if sk != NULL then we also have a reference + */ + *ugid_lookupp = linux_lookup(proto, + src_ip.s_addr, htons(src_port), + dst_ip.s_addr, htons(dst_port), + skb, oif ? 1 : 0, ugp); - filp = skb->sk->sk_socket->file; - if (filp == NULL) + } + if (*ugid_lookupp < 0) return 0; -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,28) -/* use the current's real uid/gid */ -#define UID f_uid -#define GID f_gid -#else /* 2.6.29 */ -/* use the current's file access real uid/gid */ -#define UID f_cred->fsuid -#define GID f_cred->fsgid -#endif - - if (insn->o.opcode == O_UID) { - if (filp->UID != (uid_t)insn->d[0]) - return 0; - } + 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]); - if (insn->o.opcode == O_GID) { - if (filp->GID != (gid_t)insn->d[0]) - return 0; - } + return match; - return 1; +#else /* FreeBSD */ -#else /* FreeBSD original code */ struct inpcbinfo *pi; int wildcard; struct inpcb *pcb; @@ -2267,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 */ @@ -2577,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; @@ -2592,7 +2586,7 @@ again: * the target rule. */ -check_body: +/* check_body: */ cmdlen = F_LEN(cmd); /* * An OR block (insn_1 || .. || insn_n) has the @@ -2644,7 +2638,7 @@ check_body: proto, oif, dst_ip, dst_port, src_ip, src_port, &fw_ugid_cache, - &ugid_lookup, args->inp, m->m_skb); + &ugid_lookup, (struct inpcb *)args->m); break; case O_RECV: @@ -3172,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: @@ -3191,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; @@ -3235,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, @@ -3243,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: @@ -3259,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: @@ -3286,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 @@ -3295,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); @@ -3305,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: /* @@ -3339,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; @@ -3359,8 +3396,11 @@ 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: @@ -3371,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: @@ -3380,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; @@ -3395,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; @@ -3403,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 @@ -3425,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"); @@ -4141,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 @@ -4153,7 +4209,8 @@ ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space) int i; time_t boot_seconds; - boot_seconds = boottime.tv_sec; + 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) { @@ -4179,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; @@ -4211,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); } @@ -4253,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 @@ -4264,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 @@ -4278,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.