/* * The rule engine, shared by both halves of fw: request filtering (the * ctl layer) and packet filtering (the wire). One rule language, two enforcement points: a rule says what * may happen, and the caller decides where it is enforced. */ typedef struct Rule Rule; /* * Direction, not layer. A "connect" written to a ctl file and an * egress packet are the same intent seen from two places, so they are * the same verb and one rule file serves both enforcement points. */ enum { Vin, /* inbound: announce, or a packet arriving */ Vout, /* outbound: connect, or a packet leaving */ Vany, }; struct Rule { int allow; int verb; char *proto; /* nil: any */ int anyip; uchar ip[IPaddrlen]; /* the peer, whichever end that is */ uchar mask[IPaddrlen]; int port; /* peer port, -1: any */ int lport; /* local port, -1: any */ int log; /* note matches in /sys/log/fw */ long hits; /* how often it has decided something */ int nr; Rule *next; }; /* * Rules are swapped wholesale, never mutated in place, so no packet is * ever judged against a half-applied rule set. rulechanged, if set, is * called after a swap - the wire half uses it to re-check live flows. */ extern Rule *rules; extern void (*rulechanged)(void); 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 */ void dumprules(void); void checklogging(void); /* * One question for the rule list, and its answer, in the caller's * frame. * * matchrule used to hand back a Rule* and a pointer into a static * buffer, and callers read both after it had let go of the lock. A * rule set installed in between freed the Rule under them, and two * procs deciding at once overwrote each other's reason - in a program * whose entire output is the reason. Nothing here outlives the Match, * and the Match belongs to whoever asked. * * count says to charge the decision to the rule's tally. Re-checking * live flows after a rule change is not traffic and must not be * counted, or "how often has this rule decided something" answers a * different question every time the rules are edited. */ typedef struct Match Match; struct Match { int verb; /* in */ char *proto; /* nil: any */ uchar *ip; /* the peer; unread if anyip */ int anyip; int port; /* peer port, -1: any */ int lport; /* local port, -1: any */ int count; /* charge this to the rule */ int nr; /* out: the rule that decided, 0 if none */ int log; /* it asked to be logged */ char err[128]; /* why not, if it said no */ }; int matchrule(Match*); /* 1 to permit, 0 to refuse */ int protoname2num(char*); char* protonum2name(int); void* emalloc(ulong); char* estrdup(char*);