diff options
Diffstat (limited to 'fw/src')
| -rw-r--r-- | fw/src/fw.c | 49 | ||||
| -rw-r--r-- | fw/src/rules.c | 67 | ||||
| -rw-r--r-- | fw/src/rules.h | 4 |
3 files changed, 83 insertions, 37 deletions
diff --git a/fw/src/fw.c b/fw/src/fw.c index 3c13182..ef4aff0 100644 --- a/fw/src/fw.c +++ b/fw/src/fw.c @@ -508,8 +508,6 @@ static char *ctltext = "changes take effect at once, and live connections that the\n" "new rules forbid are dropped rather than left running.\n"; -enum { Rulebuf = 64*1024 }; - /* * ctl edits are done by writing the rule set back out as ndb, editing * the text, and parsing the whole thing again. It is not the quickest @@ -562,12 +560,11 @@ editrules(char *add, int atfront, int delete) char *cur, *all, *err, *p, *nl; int i; - if((cur = mallocz(Rulebuf, 1)) == nil) + if((cur = rulestext()) == nil) return "out of memory"; - cur[fmtrules(cur, Rulebuf-1)] = '\0'; if(delete > 0){ - /* fmtrules writes one line per rule, so line n is rule n */ + /* rulestext writes one line per rule, so line n is rule n */ p = cur; for(i = 1; i < delete && p != nil; i++) if((p = strchr(p, '\n')) != nil) @@ -618,9 +615,9 @@ saverules(char *file) if(file == nil) return "no rule file to save to"; - if((buf = mallocz(Rulebuf, 1)) == nil) + if((buf = rulestext()) == nil) return "out of memory"; - n = fmtrules(buf, Rulebuf-1); + n = strlen(buf); if((fd = create(file, OWRITE, 0644)) < 0){ free(buf); return "cannot create the rule file"; @@ -653,20 +650,27 @@ flushflows(void) return nil; } +/* allocated to fit, for the reason rulestext is */ static char* flowtext(void) { char *buf, *p, *e; Flow *f; - long now; + long now, sz; int i; - if((buf = mallocz(Rulebuf, 1)) == nil) - return nil; - p = buf; - e = buf + Rulebuf; now = time(0); lock(&flowlock); + sz = 1; + for(i = 0; i < Nflow; i++) + for(f = flowtab[i]; f != nil; f = f->next) + sz += 160; + if((buf = malloc(sz)) == nil){ + unlock(&flowlock); + return nil; + } + p = buf; + e = buf + sz; for(i = 0; i < Nflow; i++) for(f = flowtab[i]; f != nil; f = f->next) p = seprint(p, e, "%s %s %I!%d -> %I!%d idle %ld\n", @@ -738,20 +742,17 @@ fsdestroyfid(Fid *fid) static void fsread(Req *r) { - char *s; - long n; + char *s, *t; switch((int)(uintptr)r->fid->file->aux){ case Qctl: readstr(r, ctltext); break; case Qrules: - if((s = mallocz(Rulebuf, 1)) == nil){ + if((s = rulestext()) == nil){ respond(r, "out of memory"); return; } - n = fmtrules(s, Rulebuf-1); - s[n] = '\0'; readstr(r, s); free(s); break; @@ -764,14 +765,18 @@ fsread(Req *r) free(s); break; case Qstats: - if((s = mallocz(Rulebuf, 1)) == nil){ + if((s = hitstext()) == nil){ + respond(r, "out of memory"); + return; + } + if((t = smprint("passed %d\ndropped %d\n\n%s", nallow, ndeny, s)) == nil){ + free(s); respond(r, "out of memory"); return; } - n = snprint(s, Rulebuf-1, "passed %d\ndropped %d\n\n", nallow, ndeny); - fmthits(s+n, Rulebuf-1-n); - readstr(r, s); free(s); + readstr(r, t); + free(t); break; default: respond(r, "not a readable file"); @@ -1259,7 +1264,7 @@ threadmain(int argc, char **argv) fmtinstall('I', eipfmt); fmtinstall('V', eipfmt); fmtinstall('E', eipfmt); - fmtinstall('M', eipfmt); /* fmtrules prints masks with it */ + fmtinstall('M', eipfmt); /* rulestext prints masks with it */ rulepath = argv[0]; readrules(rulepath); diff --git a/fw/src/rules.c b/fw/src/rules.c index b5992b0..82a31a5 100644 --- a/fw/src/rules.c +++ b/fw/src/rules.c @@ -302,16 +302,47 @@ readrules(char *file) /* * The current set, written back out as ndb. What comes out here must * parse back in unchanged; it is what gets persisted. + * + * Allocated to fit, not written into 64K and clipped. A rule set that + * outgrew the buffer used to come back short, and since prepend, append + * and delete all work by formatting the set out, editing the text and + * parsing it again, editing one rule past the limit deleted every rule + * after it. Silently. */ -long -fmtrules(char *buf, long nbuf) +static long +rulesize(Rule *r) +{ + long n; + + /* + * "allow=out" and the fixed part of every attribute, an address + * and a mask at their longest, two ports, log=yes, the tabs and + * the newline. Only the protocol is unbounded, and it is ndb's + * word rather than anything we choose. + */ + n = 160; + if(r->proto != nil) + n += strlen(r->proto); + return n; +} + +char* +rulestext(void) { - char *p, *e; + char *buf, *p, *e; + long sz; Rule *r; - p = buf; - e = buf + nbuf; lock(&rulelock); + sz = 1; + for(r = rules; r != nil; r = r->next) + sz += rulesize(r); + if((buf = malloc(sz)) == nil){ + unlock(&rulelock); + return nil; + } + p = buf; + e = buf + sz; for(r = rules; r != nil; r = r->next){ p = seprint(p, e, "%s=%s", r->allow ? "allow" : "deny", r->verb == Vin ? "in" : r->verb == Vout ? "out" : "*"); @@ -328,7 +359,8 @@ fmtrules(char *buf, long nbuf) p = seprint(p, e, "\n"); } unlock(&rulelock); - return p - buf; + USED(p); + return buf; } /* @@ -375,18 +407,26 @@ dumprules(void) * The rules with a count of how often each has decided something. A * rule that has never fired is either dead or protecting you from * something that has not happened yet, and it is worth being able to - * tell which. Kept out of fmtrules so that what "rules" prints stays + * tell which. Kept out of rulestext so that what "rules" prints stays * a rule set that can be written straight back. */ -long -fmthits(char *buf, long nbuf) +char* +hitstext(void) { - char *p, *e; + char *buf, *p, *e; + long sz; Rule *r; - p = buf; - e = buf + nbuf; lock(&rulelock); + sz = 1; + for(r = rules; r != nil; r = r->next) + sz += 64 + (r->proto != nil ? strlen(r->proto) : 0); + if((buf = malloc(sz)) == nil){ + unlock(&rulelock); + return nil; + } + p = buf; + e = buf + sz; for(r = rules; r != nil; r = r->next) p = seprint(p, e, "%-8ld %s=%s%s%s\n", r->hits, r->allow ? "allow" : "deny", @@ -394,7 +434,8 @@ fmthits(char *buf, long nbuf) r->proto != nil ? "\tproto=" : "", r->proto != nil ? r->proto : ""); unlock(&rulelock); - return p - buf; + USED(p); + return buf; } int diff --git a/fw/src/rules.h b/fw/src/rules.h index f2c38d4..7d7fe1b 100644 --- a/fw/src/rules.h +++ b/fw/src/rules.h @@ -45,8 +45,8 @@ void readrules(char*); /* parse and install, fatal on error */ Rule* parserules(char*, char**); /* parse only; nil + reason on error */ void installrules(Rule*); /* swap in, then call rulechanged */ void freerules(Rule*); -long fmtrules(char*, long); /* current set, back in ndb form */ -long fmthits(char*, long); /* the same, with hit counts */ +char* rulestext(void); /* current set as ndb; free it */ +char* hitstext(void); /* the same, with hit counts */ void dumprules(void); void checklogging(void); /* |
