/* 1740, Fri 8 Dec 00 (PST) NMC_PARS.C: Scanner/parser for nmc config and rules files Copyright (C) 1992-2002 by Nevil Brownlee, CAIDA | University of Auckland */ /* * $Log: nmc_pars.c,v $ * Revision 1.1.1.2.2.14 2002/02/23 01:57:21 nevil * Moving srl examples to examples/ directory. Modified examples/Makefile.in * * Revision 1.1.1.2.2.12 2001/05/24 02:19:44 nevil * LfapMet implemented by Remco Poortinga. * MinPDUs implemented by Nevil. * * Revision 1.1.1.2.2.9 2000/11/29 21:40:10 nevil * Bug fixes for stream / packet queue handling * * Revision 1.1.1.2.2.8 2000/08/21 01:09:14 nevil * Don't let getarg() result contain semicolons * * Revision 1.1.1.2.2.7 2000/08/08 19:44:45 nevil * 44b8 release * * Revision 1.1.1.2.2.5 2000/06/06 03:38:12 nevil * Combine NEW_ATR with TCP_ATR, various bug fixes * * Revision 1.1.1.2.2.2 2000/01/12 02:57:04 nevil * Implement 'packet pair matched' turnaroundtime distribution attributes. * Fix ASN-related bugs in NeTraMet, distribution-related bugs in fd_filter. * * Revision 1.1.1.2.2.1 1999/11/29 00:17:21 nevil * Make changes to support NetBSD on an Alpha (see version.history for details) * * Revision 1.1.1.2 1999/10/03 21:06:18 nevil * *** empty log message *** * * Revision 1.1.1.1.2.8 1999/09/22 05:38:36 nevil * Improve code to work properly on 64-bit machines * - Add OS=ALPHA handling to configure.in * - Clean up the Alpha compiler warnings * - Change all the snmp-related code to use Bit32 instead of unsigned long * * Revision 1.1.1.1.2.7 1999/09/14 00:46:47 nevil * 4.3 Release .. * - Implement -D option to run NeMaC as a daemon * - Tidy up the on-line help displays * - Make IPv4 the default PeerType for sfmt_attribute() * * Revision 1.1.1.1.2.6 1999/05/18 03:36:26 nevil * Implement IPv6 in NeTraMet, and its manager/collectors. * - This is controlled by the V6 #define * - NeTraMet recognises v6 packets and fishes through their extension * headers until it finds the actual payload. * - NeMaC et al display v6 addresses in the fom specified by RFC 2373 * - fd_util and fd_extract allow colons in addresses (for defining tags) * * Revision 1.1.1.1.2.5 1999/02/03 04:41:43 nevil * Implementation of TCP attributes, part 5 * * Revision 1.1.1.1.2.4 1999/01/27 04:26:14 nevil * Minor corrections to fix compiler warnings * * Revision 1.1.1.1.2.3 1999/01/20 04:01:34 nevil * Implementation of TCP attributes, part 4 * * Revision 1.1.1.1.2.2 1999/01/08 01:38:32 nevil * Distribution file for 4.3b7 * * Revision 1.1.1.1.2.1 1998/11/25 03:33:23 nevil * Implement tcpdata (part 2) * * Revision 1.1.1.1 1998/11/16 03:57:27 nevil * Import of NeTraMet 4.3b3 * * Revision 1.1.1.1.2.2 1998/11/13 01:43:24 nevil * Test implementation of distribution-valued attributes used a special * parse routine (getdistparams) for their value and mask. This has * been deleted now that SRL makes it easy to write rules using them. * * Revision 1.1.1.1.2.1 1998/11/11 23:14:39 nevil * Only include malloc.h if we HAVE_MALLOC_H * * Revision 1.1.1.1 1998/10/28 20:31:25 nevil * Import of NeTraMet 4.3b1 * * Revision 1.1.3.2.2.1 1998/10/23 03:56:05 nevil * Change log_msg() to write to stderr if no log file is available * * Revision 1.1.3.2 1998/10/18 23:44:10 nevil * Added Nicolai's patches, some 'tidying up' of the source * * Revision 1.1.3.1 1998/10/13 02:48:24 nevil * Import of Nicolai's 4.2.2 * * Revision 1.1.1.1 1998/08/24 12:09:28 nguba * NetraMet 4.2 Original Distribution * * Revision 1.11 1998/07/21 00:43:57 rtfm * Change attrib numbers for 'New Attribs' I-D * First release version of SRL * * Revision 1.4 1998/04/23 03:17:52 rtfm * Added final add_rule(*, NULL) call to flush rule download buffer * * Revision 1.3 1998/04/22 22:23:19 kawai * Added checks to prevent buffer over runs in get_args * All errors and debugging output now go to stderr * * Revision 1.2 1998/03/13 03:54:37 kawai * -Replace check_log by log_msg which does the complete processing * of log messages * -Added some more diagnostics for failed fopens */ #if HAVE_CONFIG_H #include #endif #define RULETEST_DEBUG 0 #include #include #include #include #include #ifdef _AIX #define _XOPEN_EXTENDED_SOURCE /* Needed to get syslog defined properly */ #endif #include #ifdef _AIX #undef _XOPEN_EXTENDED_SOURCE #endif #include #if HAVE_MALLOC_H # include #endif #include #include #include #include #include #if HAVE_SYS_SELECT_H #include #endif #include "ausnmp.h" #include "asn1.h" #include "snmp.h" #include "snmpimpl.h" #include "snmpapi.h" #include "snmpclnt.h" #include "mib.h" #include "nmc.h" #include "nmc_c64.h" void log_msg(int priority, int die, char *fmt, ...) { va_list ap; time_t t; if (testing) { va_start(ap, fmt); fprintf(stderr, "<><><> "); vfprintf(stderr, fmt, ap); } #ifdef LOG_LOCAL va_start(ap, fmt); if (syslog_name[0]) { vsyslog(priority, fmt, ap); } #endif if (logfile[0] != '\0') { if (append_log && (logfl = fopen(logfile,"a")) == 0) { if (syslog_name[0]) syslog(LOG_ERR, "Failed to open logfile '%s':%s\n", logfile, strerror(errno)); else fprintf(stderr,"Failed to open logfile '%s':%s\n", logfile, strerror(errno)); } if (logfl == NULL) /* Couldn't open log file */ fprintf(stderr, "failed to open %s %s\n",logfile, strerror(errno)); } if (logfl == NULL) { /* No log file available */ logfl = stderr; append_log = 0; } time(&t); fprintf(logfl, "%s -- ", fmt_time(&t)); va_start(ap, fmt); vfprintf(logfl, fmt, ap); /* Was fprintf! Nevil, 10 Sep 98 */ va_end(ap); if (append_log) fclose(logfl); else fflush(logfl); if (die) exit(die); } void mswait(unsigned int ms) /* Wait for ms milliseconds */ { struct timeval timeout; timeout.tv_sec = ms/1000; timeout.tv_usec = (long)(ms%1000)*1000L; select(FD_SETSIZE, 0, 0, 0, &timeout); } FILE *wfopen(char *lfn, char *fn) /* Open next file in sequence for write */ { int n; FILE *f; for (n = 1; ; ++n) { sprintf(lfn,"%s.%03d",fn,n); if ((f = fopen(lfn,"r")) == NULL) { if ((f = fopen(lfn,"w")) != NULL) return f; if (syslog_name[0]) syslog(LOG_ERR, "Failed to open logfile '%s':%s\n", lfn, strerror(errno)); else fprintf(stderr,"Failed to open logfile '%s':%s\n", lfn, strerror(errno)); exit(0); } fclose(f); } } char *strmov(char *d, char *s) { while (*s != '\0') *d++ = *s++; return d; } char *gnbr(unsigned int *n, char *s) /* Get nbr from 's', return updated 's' */ { unsigned int v = 0, b = 10, d; while (*s == ' ') ++s; if (*s == 'x' || *s == 'X') { ++s; b = 16; } else if (*s == '0') { ++s; b = 8; } for (;;) { d = *s; if (b == 16) { if (!isxdigit(d)) break; } else { if (!isdigit(d)) break; if (b == 8 && d > '7') break; } if (d <= '9') d -= '0'; else if (d <= 'F') d -= ('A'-10); else d -= ('a'-10); v = v*b + d; ++s; } *n = v; return s; } char *gcstring(char *s, int *len) /* Get string from s */ { static char escin[] = { 'b', 'f', 'n', 'r', 't', 'v','\\','\'','\"','\?', 0 }; static char escout[] ={ '\b','\f','\n','\r','\t','\v','\\','\'','\"','\?' }; unsigned int c,j; char sbuf[80], *t = sbuf, *rp; while (*s) { if (*s == '\\') { ++s; c = *s; if (c == '0' || c == 'x' || c == 'X') { /* Octal or hex nbr */ s = gnbr(&c,s); *t++ = c; } else if (isdigit(c)) { /* Octal number */ --s; *s = '0'; /* Make gnbr use base 8 */ s = gnbr(&c,s); *t++ = c; } else { j = 0; do { if (c == escin[j]) break; } while (escin[++j] != 0); if (escin[j] != 0) { *t++ = escout[j]; ++s; } } } else *t++ = *s++; } *t = '\0'; *len = t-sbuf; rp = (char *)malloc(*len+1); strcpy(rp,sbuf); return rp; } static char ftb[32]; char *fmt_time(time_t *ti) { if (!utc_time) { char *ts = ctime(ti); strncpy(&ftb[0], &ts[11], 9); /* 17:31:42_ */ strncpy(&ftb[9], &ts[0], 4); /* Thu_ */ strncpy(&ftb[13], &ts[8], 3); /* 23_ */ strncpy(&ftb[16], &ts[4], 4); /* Sep_ */ strncpy(&ftb[20], &ts[20], 4); /* 1997 */ ftb[24] = '\0'; } else { struct tm *t = gmtime(ti); char *dow[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; char *moy[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; sprintf(ftb, "%02d:%02d:%02d %s %2d %s %4d", t->tm_hour,t->tm_min,t->tm_sec, dow[t->tm_wday], t->tm_mday, moy[t->tm_mon], t->tm_year+1900); } return ftb; } char *uptime_string(unsigned long timeticks, char *buf) { int seconds, minutes, hours, days; timeticks /= 100; days = timeticks / (60 * 60 * 24); timeticks %= (60 * 60 * 24); hours = timeticks / (60 * 60); timeticks %= (60 * 60); minutes = timeticks / 60; seconds = timeticks % 60; if (days == 0){ sprintf(buf, "%d:%02d:%02d", hours, minutes, seconds); } else if (days == 1) { sprintf(buf, "%d day, %d:%02d:%02d", days, hours, minutes, seconds); } else { sprintf(buf, "%d days, %d:%02d:%02d", days, hours, minutes, seconds); } return buf; } #if V6 char *sfmt_v6addr(char *d, unsigned char *a) { char buf[50]; int j, k, st,len, stx,lenx; unsigned int v, a2[IP6_ADDR_LEN/2], av; st = len = lenx = 0; for (k = j = 0; j != IP6_ADDR_LEN; j += 2) { v = (a[j] << 8) | a[j+1]; a2[k++] = v; /* Build array of two-byte pairs */ if (v == 0) ++len; else { if (len > lenx) { /* Find longest run of zero pairs */ stx = st; lenx = len; } st = k; len = 0; } } if (len > lenx) { stx = st; lenx = len; } if (lenx != 0 && stx == 0) { /* Longest run at left */ d = strmov(d, ":"); j = lenx; } else { sprintf(buf, "%04X", a2[0]); d = strmov(d,buf); j = 1; } for (; j < IP6_ADDR_LEN/2; ) { if (lenx != 0 && j == stx) { d = strmov(d,":"); j += lenx; } else { sprintf(buf, ":%04X", a2[j]); d = strmov(d, buf); ++j; } } if (j == stx+lenx) d = strmov(d, ":"); /* Longest run at right */ *d = '\0'; return d; } #endif char *sfmt_address(char *d, unsigned char *a, unsigned char addrtype, unsigned char addrsz) { int j; char buf[50]; switch (addrtype) { case ADJ_ADDR: #if defined(NETFLOW) switch (addrsz) { case IP4_ADDR_LEN: sprintf(buf,"%u", a[0]); d = strmov(d,buf); for (j = 1; j != addrsz; ++j) { sprintf(buf,".%u", a[j]); d = strmov(d,buf); } break; default: sprintf(buf,"%02X", a[0]); d = strmov(d,buf); for (j = 1; j != addrsz; ++j) { sprintf(buf,"-%02X", a[j]); d = strmov(d,buf); } break; } break; #else sprintf(buf,"%02X", a[0]); d = strmov(d,buf); for (j = 1; j != addrsz; ++j) { sprintf(buf,"-%02X", a[j]); d = strmov(d,buf); } break; #endif case PEER_ADDR: switch (addrsz) { case MAC_ADDR_LEN: case NSAP_ADDR_LEN: case TRANS_ADDR_LEN: sprintf(buf,"%02X", a[0]); d = strmov(d,buf); for (j = 1; j != addrsz; ++j) { sprintf(buf,"-%02X", a[j]); d = strmov(d,buf); } break; #if V6 case IP6_ADDR_LEN: sfmt_v6addr(buf, a); d = strmov(d, buf); break; #endif default: sprintf(buf,"%u", a[0]); d = strmov(d,buf); for (j = 1; j != addrsz; ++j) { sprintf(buf,".%u", a[j]); d = strmov(d,buf); } break; } break; case TRANS_ADDR: sprintf(buf,"%u", a[0] << 8 | a[1]); d = strmov(d,buf); break; } return d; } #ifdef NEW_ATR char *sfmt_distrib(char *data, struct distribution *dp) { char buf[1200]; int nb,j; if (dp->Transform == DS_NULL) return strmov(data, "0"); sprintf(buf,"%d %d %d %d %d %d %d %d ", dp->Transform, dp->ScaleFactor, dp->LowerLimit, dp->UpperLimit, dp->Buckets, dp->Parameter1, dp->Parameter2, dp->Parameter3); data = strmov(data, buf); nb = dp->Transform == DS_DYN_PTS ? dp->Buckets : dp->Buckets+1; for (j = 0; j != nb; ++j) { sprintf(buf," %d", dp->counts[j]); data = strmov(data, buf); } return data; } char *sfmt_tcp_data(char *data, struct subflow_data *sfd) { char buf[500]; int j; if (sfd == NULL || !sfd->valid) return strmov(data, "0"); sprintf(buf,"%lu %lu ", sfd->n_subflows, sfd->mx_active_subflows); data = strmov(data, buf); data = putc64(data, &sfd->ToTCPLenOctets); data = strmov(data, " "); data = putc64(data, &sfd->FromTCPLenOctets); data = strmov(data, " "); data = putc64(data, &sfd->ToTCPSeqOctets); data = strmov(data, " "); data = putc64(data, &sfd->FromTCPSeqOctets); data = strmov(data, " "); data = putc64(data, &sfd->ToTCPAckOctets); data = strmov(data, " "); data = putc64(data, &sfd->FromTCPAckOctets); sprintf(buf," %lu %lu", sfd->ToTCPDecrSeq, sfd->FromTCPDecrSeq); data = strmov(data, buf); return data; } #endif /* NEW_ATR */ void printruleaddress(FILE *f, unsigned char *a) { int j, k; fprintf(f,"%u", a[0]); for (k = RULE_ADDR_LEN-1; k != 0; --k) if (a[k] != 0) break; for (j = 1; j <= k; ++j) fprintf(f,".%u", a[j]); } int parse_open(char *fn) /* Open file and initialise parser */ { if ((rfp = fopen(fn, "r")) == NULL) { rferrors = 1; return 0; } rfwarnings = rferrors = rule_line = 0; ic = '\n'; lic = ' '; strcpy(scan_rfname,fn); /* Remember rule file's name */ return 1; } void push_include(char *ifp) { struct incl_ent *iep; if (incl_depth == MXINCL) { p_error("Includes nested too deep"); return; } iep = &incl_stack[incl_depth]; iep->fp = rfp; if ((rfp = fopen(ifp, "r")) == NULL) { p_error("Couldn't open include file"); rfp = iep->fp; return; } ++incl_depth; strcpy(iep->buf,inbuf); iep->bp = ibp; iep->line_nbr = rule_line; iep->iblisted = iblisted; iep->lic = lic; iep->ic = ic; strcpy(iep->rfname,scan_rfname); strcpy(scan_rfname,ifp); /* Remember rule file's name */ rule_line = 0; ic = '\n'; } int end_of_file(void) { struct incl_ent *iep; if (ic != EOF) return 0; if (incl_depth == 0) return 1; iep = &incl_stack[--incl_depth]; rfp = iep->fp; strcpy(inbuf,iep->buf); ibp = iep->bp; rule_line = iep->line_nbr; iblisted = iep->iblisted; lic = iep->lic; ic = iep->ic; strcpy(scan_rfname,iep->rfname); return 0; } int trailing_arg() { for (;;) { if (end_of_file() || lic == '\n') return 0; /* No trailing argument */ if (!isspace(ic)) break; nextchar(); } return 1; /* We have a trailing argument */ } void getarg(char *arg) { int count = 1; /* Space for trailing null */ for (;;) { if (end_of_file()) { *arg = '\0'; return; } if (!isspace(ic)) break; nextchar(); } do { *arg++ = ic; nextchar(); } while (!isspace(ic) && ic != ';' && ++count < NAME_LN && !end_of_file() ); *arg = '\0'; return; } int nextchar() { lic = ic; for (;;) { if (lic == '\n') { if (fgets(inbuf, sizeof(inbuf), rfp) == NULL) { ic = EOF; if (end_of_file()) return EOF; } else { iblisted = 0; ++rule_line; ibp = inbuf; if (listrules && pass == 1) p_error(NULL); } } ic = *ibp++; if (ic == '#') lic = '\n'; /* Ignore comments */ else return ic; } } int wordis(p,w) char *p, *w; { if (strlen(p) != strlen(w)) return 0; /* Lengths differ */ return strcmp(p,w) == 0; } void p_error(char *msg) { if (!iblisted) { printf("%s %4d: %s", scan_rfname,rule_line,inbuf); iblisted = 1; } if (msg) { printf("%s !!!\n", msg); ++rferrors; } } void p_warn(char *msg) { if (!iblisted) { printf("%s %4d: %s", scan_rfname,rule_line,inbuf); iblisted = 1; } if (msg) { printf("%s <<< warning\n", msg); ++rfwarnings; } } int lookup(char *id) /* Return 1 if id is already in table */ { int id_len, j; unsigned int hash; struct symbol *lsp, *sp; id_len = strlen(id); if (id_len > SYMBOLSZ) { sprintf(err_msg, "Id %s has more than %d chars", id,id_len); p_warn(err_msg); id_len = SYMBOLSZ; } hash = id_len; for (j = 0; j != id_len; ++j) hash += id[j]; st_index = hash & STHASHMASK; sp = &symbol_table[st_index]; lsp = NULL; if (sp->id[0] != 0) { /* At least one entry for this hash */ if (strcmp(sp->id,id) == 0) { toktype = sp->type; toklen = sp->size; return 1; } else { for (;;) { lsp = sp; if (lsp->next == 0) break; /* End of chain */ sp = &symbol_table[st_index = lsp->next]; if (strcmp(sp->id,id) == 0) { toktype = sp->type; toklen = sp->size; return 1; } } } } /* Not there, put it in */ if (lsp != NULL) { /* Add to hash chain */ if (st_top == STSIZE) { sprintf(err_msg, "More than %d symbols",STSIZE); p_error(err_msg); } else { /* Add new symbol */ st_index = st_top++; lsp->next = st_index; sp = &symbol_table[st_index]; } } memset(sp, 0, sizeof(struct symbol)); strncpy(sp->id, id, id_len); sp->id[id_len] = '\0'; return 0; /* Not already in ST, now added */ } void add_symbol(char *id, int type, int value) { struct symbol *sp; lookup(id); sp = &symbol_table[st_index]; sp->type = type; sp->value = value; } void dump_symbol_table() { int j; struct symbol *sp; for (j = 0; j != st_top; ++j) { sp = &symbol_table[j]; if (sp->id[0] != 0) { printf("%5d, %5d: %s type=%d, value=%d, size=%d\n", j, sp->next, sp->id, sp->type,sp->value,sp->size); } } } void init_symbol_table() { int j; st_top = STHASHBASE; for (j = 0; j != STHASHBASE; ++j) symbol_table[j].id[0] = '\0'; if (MIBver == 4) { add_symbol("ip", TOK_WORD, AT_IP4); add_symbol("ipx", TOK_WORD, AT_NOVELL); add_symbol("novell", TOK_WORD, AT_NOVELL); add_symbol("decnet", TOK_WORD, AT_DECNET); add_symbol("ethertalk", TOK_WORD, AT_ETHERTALK); add_symbol("clns", TOK_WORD, AT_CLNS); add_symbol("other", TOK_WORD, AT_OTHER); add_symbol("dummy", TOK_WORD, AT_DUMMY); } else { add_symbol("ip", TOK_WORD, old_addr_type[AT_IP4]); add_symbol("ipx", TOK_WORD, old_addr_type[AT_NOVELL]); add_symbol("novell", TOK_WORD, old_addr_type[AT_NOVELL]); add_symbol("decnet", TOK_WORD, old_addr_type[AT_DECNET]); add_symbol("ethertalk", TOK_WORD, old_addr_type[AT_ETHERTALK]); add_symbol("clns", TOK_WORD, old_addr_type[AT_CLNS]); add_symbol("other", TOK_WORD, old_addr_type[AT_OTHER]); add_symbol("dummy", TOK_WORD, old_addr_type[AT_DUMMY]); } add_symbol("countpkt", TOK_ACTION, RA_COUNTPKT); add_symbol("count", TOK_ACTION, RA_COUNT); add_symbol("succeed", TOK_ACTION, RA_SUCCEED); add_symbol("nomatch", TOK_ACTION, RA_FAIL); add_symbol("retry", TOK_ACTION, RA_FAIL); add_symbol("fail", TOK_ACTION, RA_FAIL); add_symbol("pushtoact", TOK_ACTION, RA_PUSHTOACT); add_symbol("pushto", TOK_ACTION, RA_PUSHTO); add_symbol("gotoact", TOK_ACTION, RA_GOTOACT); add_symbol("goto", TOK_ACTION, RA_GOTO); add_symbol("gosubact", TOK_ACTION, RA_GOSUBACT); add_symbol("gosub", TOK_ACTION, RA_GOSUB); add_symbol("return", TOK_ACTION, RA_RETURN); add_symbol("assignact", TOK_ACTION, RA_ASSIGNACT); add_symbol("assign", TOK_ACTION, RA_ASSIGN); add_symbol("ignore", TOK_ACTION, RA_IGNORE); add_symbol("pushruletoact", TOK_ACTION, RA_PUSHTOACT); add_symbol("pushruleto", TOK_ACTION, RA_PUSHTO); add_symbol("pushpkttoact", TOK_ACTION, RA_PUSHPKTTOACT); add_symbol("pushpktto", TOK_ACTION, RA_PUSHPKTTO); add_symbol("poptoact", TOK_ACTION, RA_POPTOACT); add_symbol("popto", TOK_ACTION, RA_POPTO); add_symbol("set", TOK_WORD, RF_SET); add_symbol("rules", TOK_WORD, RF_RULES); add_symbol("format", TOK_WORD, RF_FORMAT); add_symbol("statistics", TOK_WORD, RF_STATS); add_symbol("next", TOK_WORD, RF_NEXT); add_symbol("include", TOK_WORD, RF_INCLUDE); add_symbol("icmp", TOK_WORD, PT_ICMP); add_symbol("tcp", TOK_WORD, PT_TCP); add_symbol("udp", TOK_WORD, PT_UDP); add_symbol("ospf", TOK_WORD, PT_OSPF); add_symbol("ftpdata", TOK_WORD, WNP_FTPDATA); add_symbol("ftp", TOK_WORD, WNP_FTP); add_symbol("http", TOK_WORD, WNP_WWW); add_symbol("telnet", TOK_WORD, WNP_TELNET); add_symbol("smtp", TOK_WORD, WNP_SMTP); add_symbol("domain", TOK_WORD, WNP_DOMAIN); add_symbol("nntp", TOK_WORD, WNP_NNTP); add_symbol("ntp", TOK_WORD, WNP_NTP); add_symbol("snmp", TOK_WORD, WNP_SNMP); add_symbol("gopher", TOK_WORD, WNP_GOPHER); add_symbol("www", TOK_WORD, WNP_WWW); for (j = 0; j != SZ_ATTRIBS; ++j) { add_symbol(attribs[j].name, TOK_ATTRIB, attribs[j].index); symbol_table[st_index].size = attribs[j].len; } } int getword() { char wbuf[30], *wp = wbuf; struct symbol *sp; int r; for (;;) { *wp++ = tolower(ic); nextchar(); if (end_of_file()) return EOF; if (!isalnum(ic) && ic != '_') break; } *wp = '\0'; r = lookup(wbuf); sp = &symbol_table[st_index]; if (r) { /* Found in ST */ if (sp->type == TOK_SYMBOL) return RF_SYMBOL; /* Label with unknown address */ else return sp->value; } sp->type = toktype = TOK_SYMBOL; /* New symbol */ /* sp->value is initially 0 */ return RF_SYMBOL; } int getnbr(int maxnbr) /* NB, 22 Oct 93 */ { int v = 0; toktype = TOK_OTHER; for (;;) { if (end_of_file()) return EOF; if (isdigit(ic)) break; else if (isalpha(ic)) return getword(); else nextchar(); } toktype = TOK_INT; for (;;) { v = v*10 + ic-'0'; nextchar(); if (end_of_file()) EOF; if (!isdigit(ic)) break; } if (v > maxnbr) { /* NB, 22 Oct 93 */ sprintf(err_msg, "Number > %d",maxnbr); /* NB, 22 Oct 93 */ p_error(err_msg); } return v; } unsigned int getint(unsigned int *base) { char wbuf[30], *wp; unsigned long v; unsigned char c, word; int sic; char *sibp; for (;;) { if (end_of_file()) return EOF; if (isalnum(ic)) break; if (ic == '\'') break; else nextchar(); } if (ic == '\'') { nextchar(); v = ic; nextchar(); if (ic != '\'') p_error("Missing ' in char constant"); nextchar(); if (*base == 0) *base = 10; return v; } sic = ic; sibp = ibp; /* Save scanner state */ for (word = 0, wp = wbuf; ; ) { if (isalpha(ic) && !isxdigit(ic)) word = 1; *wp++ = tolower(ic); nextchar(); if (end_of_file()) break; if (!isalnum(ic)) break; } if (word) { if (*base == 0) *base = 10; ic = sic; ibp = sibp; /* Back up scanner */ return getword(); } *wp = '\0'; if (*base == 0) *base = ic == '-' ? 16 : 10; /* Hex address bytes separated by - */ for (wp = wbuf, v = 0; *wp != '\0'; ) { c = *wp++; if (isdigit(c)) c -= '0'; else c = c-'a' + 10; v = v*(*base) + c; } return v; } void getaddress(unsigned char *a,unsigned char len, unsigned char addrsz) { unsigned int j, base, v; for (base = j = 0; j != addrsz; ++j) { v = getint(&base); if (len != 1 && /* Two or more bytes in address */ ic != '.' && ic != '-' && /* No byte separator character */ j == 0) { /* Allow 16-bit decimal in first two bytes */ a[j++] = (v>>8) & 0xFF; v &= 0x00FF; } a[j] = v; if (ic != '.' && ic != '-') { /* End of token; pad with zeroes */ for (++j; j != addrsz; ++j) a[j] = 0; return; } } while (ic == '.' || isdigit(ic)) nextchar(); /* Skip to end of v6 addresses in srl+v6 rulesets */ } int getattribute(unsigned char col, struct flow_info *fp) { switch(col) { case FTLOWINTERFACE: fp->LowInterface = getnbr(255); break; case FTLOWADJACENTTYPE: fp->LowAdjType = getnbr(255); break; case FTLOWADJACENTADDRESS: getaddress(fp->LowAdjAddress,MAC_ADDR_LEN, MAC_ADDR_LEN); break; case FTLOWADJACENTMASK: getaddress(fp->LowAdjMask,MAC_ADDR_LEN, MAC_ADDR_LEN); break; case FTLOWPEERTYPE: fp->LowPeerType = getnbr(255); break; case FTLOWPEERADDRESS: getaddress(fp->LowPeerAddress,PEER_ADDR_LEN, PEER_ADDR_LEN); break; case FTLOWPEERMASK: getaddress(fp->LowPeerMask,PEER_ADDR_LEN, PEER_ADDR_LEN); break; case FTLOWTRANSTYPE: fp->LowTransType = getnbr(255); break; case FTLOWTRANSADDRESS: getaddress(fp->LowTransAddress,TRANS_ADDR_LEN, TRANS_ADDR_LEN); break; case FTLOWTRANSMASK: getaddress(fp->LowTransMask,TRANS_ADDR_LEN, TRANS_ADDR_LEN); break; case FTHIINTERFACE: fp->HighInterface = getnbr(255); break; case FTHIADJACENTTYPE: fp->HighAdjType = getnbr(255); break; case FTHIADJACENTADDRESS: getaddress(fp->HighAdjAddress,MAC_ADDR_LEN, MAC_ADDR_LEN); break; case FTHIADJACENTMASK: getaddress(fp->HighAdjMask,MAC_ADDR_LEN, MAC_ADDR_LEN); break; case FTHIPEERTYPE: fp->HighPeerType = getnbr(255); break; case FTHIPEERADDRESS: getaddress(fp->HighPeerAddress,PEER_ADDR_LEN, PEER_ADDR_LEN); break; case FTHIPEERMASK: getaddress(fp->HighPeerMask,PEER_ADDR_LEN, PEER_ADDR_LEN); break; case FTHITRANSTYPE: fp->HighTransType = getnbr(255); break; case FTHITRANSADDRESS: getaddress(fp->HighTransAddress,TRANS_ADDR_LEN, TRANS_ADDR_LEN); break; case FTHITRANSMASK: getaddress(fp->HighTransMask,TRANS_ADDR_LEN, TRANS_ADDR_LEN); break; case FTSOURCECLASS: fp->SourceClass = getnbr(255); break; case FTDESTCLASS: fp->DestClass = getnbr(255); break; case FTFLOWCLASS: fp->FlowClass = getnbr(255); break; case FTSOURCEKIND: fp->SourceKind = getnbr(255); break; case FTDESTKIND: fp->DestKind = getnbr(255); break; case FTFLOWKIND: fp->FlowKind = getnbr(255); break; case FTDSCODEPOINT: fp->DSCodePoint = getnbr(0x3F); break; #if defined(NETFLOW) case FTMETERID: fp->MeterId = getnbr(255); break; case FTLOWROUTEASN: getaddress(fp->LowRouteASN,TRANS_ADDR_LEN, TRANS_ADDR_LEN); break; case FTLOWROUTEPREFIX: fp->LowRoutePrefix = getnbr(255); break; case FTHIROUTEASN: getaddress(fp->HighRouteASN,TRANS_ADDR_LEN, TRANS_ADDR_LEN); break; case FTHIROUTEPREFIX: fp->HighRoutePrefix = getnbr(255); break; #endif default: sprintf(err_msg,"Attribute %d not allowed",col); p_error(err_msg); } } char *sfmt_attrib(char *d, struct flow_info *fp, unsigned char col) { char buf[50]; char pal = fp->LowPeerType > MX_PROTOCOLS ? MAC_ADDR_LEN : addr_len[fp->LowPeerType]; #ifdef NEW_ATR struct distribution *dist; #endif switch(col) { case FTFLOWINDEX: /* Used to synchronise column blobs */ sprintf(buf,"%u",fp->FlowIndex); break; case FTFLOWSTATUS: sprintf(buf,"%u",fp->FlowStatus); break; case FTLOWINTERFACE: sprintf(buf,"%u",fp->LowInterface); break; case FTLOWADJACENTTYPE: sprintf(buf,"%u",fp->LowAdjType); break; case FTLOWADJACENTADDRESS: #if defined(NETFLOW) return sfmt_address(d,fp->LowAdjAddress,ADJ_ADDR, fp->LowAdjType == AT_IP4 ? IP4_ADDR_LEN : MAC_ADDR_LEN); #else return sfmt_address(d,fp->LowAdjAddress,ADJ_ADDR,MAC_ADDR_LEN); #endif case FTLOWADJACENTMASK: return sfmt_address(d,fp->LowAdjMask,ADJ_ADDR,MAC_ADDR_LEN); case FTLOWPEERTYPE: sprintf(buf,"%u",fp->LowPeerType); break; case FTLOWPEERADDRESS: return sfmt_address(d,fp->LowPeerAddress,PEER_ADDR,pal); case FTLOWPEERMASK: return sfmt_address(d,fp->LowPeerMask,PEER_ADDR,pal); case FTLOWTRANSTYPE: sprintf(buf,"%u",fp->LowTransType); break; case FTLOWTRANSADDRESS: return sfmt_address(d,fp->LowTransAddress,TRANS_ADDR,TRANS_ADDR_LEN); case FTLOWTRANSMASK: return sfmt_address(d,fp->LowTransMask,TRANS_ADDR,TRANS_ADDR_LEN); case FTHIINTERFACE: sprintf(buf,"%u",fp->HighInterface); break; case FTHIADJACENTTYPE: sprintf(buf,"%u",fp->HighAdjType); break; case FTHIADJACENTADDRESS: #if defined(NETFLOW) return sfmt_address(d,fp->HighAdjAddress,ADJ_ADDR, fp->HighAdjType == AT_IP4 ? IP4_ADDR_LEN : MAC_ADDR_LEN); #else return sfmt_address(d,fp->HighAdjAddress,ADJ_ADDR,MAC_ADDR_LEN); #endif case FTHIADJACENTMASK: return sfmt_address(d,fp->HighAdjMask,ADJ_ADDR,MAC_ADDR_LEN); case FTHIPEERTYPE: sprintf(buf,"%u",fp->HighPeerType); break; case FTHIPEERADDRESS: return sfmt_address(d,fp->HighPeerAddress,PEER_ADDR,pal); case FTHIPEERMASK: return sfmt_address(d,fp->HighPeerMask,PEER_ADDR,pal); case FTHITRANSTYPE: sprintf(buf,"%u",fp->HighTransType); break; case FTHITRANSADDRESS: return sfmt_address(d,fp->HighTransAddress,TRANS_ADDR,TRANS_ADDR_LEN); case FTHITRANSMASK: return sfmt_address(d,fp->HighTransMask,TRANS_ADDR,TRANS_ADDR_LEN); case FTRULESET: sprintf(buf,"%u",fp->FlowRuleSet); break; case FTUPOCTETS: putc64(buf, &fp->FwdBytes); break; case FTUPPDUS: putc64(buf, &fp->FwdPackets); break; case FTDOWNOCTETS: putc64(buf, &fp->BackBytes); break; case FTDOWNPDUS: putc64(buf, &fp->BackPackets); break; case FTFIRSTTIME: sprintf(buf,"%lu",fp->FirstTime); break; case FTLASTTIME: sprintf(buf,"%lu",fp->LastTime); break; case FTSOURCECLASS: sprintf(buf,"%u",fp->SourceClass); break; case FTDESTCLASS: sprintf(buf,"%u",fp->DestClass); break; case FTFLOWCLASS: sprintf(buf,"%u",fp->FlowClass); break; case FTSOURCEKIND: sprintf(buf,"%u",fp->SourceKind); break; case FTDESTKIND: sprintf(buf,"%u",fp->DestKind); break; case FTFLOWKIND: sprintf(buf,"%u",fp->FlowKind); break; case FTDSCODEPOINT: sprintf(buf,"%u",fp->DSCodePoint); break; #if defined(NETFLOW) case FTMETERID: sprintf(buf,"%u",fp->MeterId); break; case FTLOWROUTEASN: return sfmt_address(d,fp->LowRouteASN,TRANS_ADDR,TRANS_ADDR_LEN); case FTLOWROUTEPREFIX: sprintf(buf,"%u",fp->LowRoutePrefix); break; case FTHIROUTEASN: return sfmt_address(d,fp->HighRouteASN,TRANS_ADDR,TRANS_ADDR_LEN); case FTHIROUTEPREFIX: sprintf(buf,"%u",fp->HighRoutePrefix); break; #endif #ifdef NEW_ATR case FTDISTRIBUTIONS: sprintf(buf,"%0x",fp->distrib_bits); break; case FTTOPACKETSIZE: case FTFROMPACKETSIZE: case FTTOINTERARRIVALTIME: case FTFROMINTERARRIVALTIME: case FTTOTURNAROUNDTIME: case FTFROMTURNAROUNDTIME: case FTTOBITRATE: case FTFROMBITRATE: case FTTOPDURATE: case FTFROMPDURATE: case FTTOTCPSIZE: case FTFROMTCPSIZE: case FTTOTCPTIME: case FTFROMTCPTIME: case FTTOTCPRATE1: case FTFROMTCPRATE1: case FTTOTCPRATE2: case FTFROMTCPRATE2: /* case FTTOTURNAROUNDTIME1: case FTFROMTURNAROUNDTIME1: */ case FTTOTURNAROUNDTIME2: case FTFROMTURNAROUNDTIME2: case FTTOTURNAROUNDTIME3: case FTFROMTURNAROUNDTIME3: case FTTOTURNAROUNDTIME4: case FTFROMTURNAROUNDTIME4: case FTTOFLOWOCTETS: case FTFROMFLOWOCTETS: case FTTOFLOWPDUS: case FTFROMFLOWPDUS: case FTFLOWTIME: for (dist = fp->distrib_list; dist != NULL; dist = dist->next) { if (dist->selector == col) break; } if (dist == NULL) { printf("Couldn't find distribution <<"); return d; } return sfmt_distrib(d, dist); case FTTOLOSTPDUS: sprintf(buf,"%u",fp->ToLostPDUs); break; case FTFROMLOSTPDUS: sprintf(buf,"%u",fp->FromLostPDUs); break; case FTTOPQOVERFLOWS: sprintf(buf,"%u",fp->ToPQOverflows); break; case FTFROMPQOVERFLOWS: sprintf(buf,"%u",fp->FromPQOverflows); break; case FTTCPDATA: return sfmt_tcp_data(d, fp->sfd); #endif /* NEW_ATR */ default: sprintf(buf,"*"); /* Unknown attribute */ } return strmov(d,buf); } #define TR_FIN 1 #define TR_TO 2 #define TR_ACT 3 int action_type[] = { 0, TR_FIN, /* RA_IGNORE 1 */ TR_FIN, /* RA_RETRY 2 */ TR_FIN, /* RA_COUNT 3 */ TR_FIN, /* RA_COUNTPKT 4 */ TR_FIN, /* RA_RETURN 5 */ TR_TO, /* RA_GOSUB 6 */ TR_ACT, /* RA_GOSUBACT 7 */ TR_TO, /* RA_ASSIGN 8 */ TR_ACT, /* RA_ASSIGNACT 9 */ TR_TO, /* RA_GOTO 10 */ TR_ACT, /* RA_GOTOACT 11 */ TR_TO, /* RA_PUSHTO 12 */ TR_ACT, /* RA_PUSHTOACT 13 */ TR_TO, /* RA_PUSHPKTTO 14 */ TR_ACT /* RA_PUSHPKTTOACT 15 */ }; int scan_rulefile(struct meter_status *ms, int doset, int list, int standby) { struct meter_rule_info *mri; struct rule_info ri, last_ri; int only_gotoAct,last_only_gotoAct, gosub_rule,last_gosub_rule, cf,cfa; int rule_set, nrules, ncounts, n, len, kind, labels, seltype; struct flow_info ai; unsigned char a, b; char *rfname; char sbuf[100], *sp, inc_fn[NAME_LN]; char abuf[50]; if (testing) fprintf(stderr, "scan_rf(): standby=%d, pass=%d, standby rf %s, current rf %s\n", standby, pass, ms->s_ruleset.filename, ms->c_ruleset.filename); if (standby) { if (!parse_open(rfname = ms->s_ruleset.filename)) { printf(" Couldn't open standby rule file %s !!!\n", ms->s_ruleset.filename); return 0; /* Fail */ } mri = &ms->s_ruleset; } else { if (!parse_open(rfname = ms->c_ruleset.filename)) { printf(" Couldn't open rule file %s !!!\n", ms->c_ruleset.filename); return 0; /* Fail */ } mri = &ms->c_ruleset; } ri.RuleSet = mri->ri_Index; /* Meter ruleinfo row index */ #if LINERAR_SEARCH MIBver = ms->MIBver; #endif rule_set = 0; nrules = ncounts = 0; kind = RF_RULES; last_only_gotoAct = last_gosub_rule = 0; memset(&last_ri, 0, sizeof(last_ri)); for (;;) { cf = cfa = 0; do { /* First char of a line */ nextchar(); if (end_of_file()) break; } while (lic != '\n'); if (end_of_file()) break; n = getnbr(255); /* What kind of line is it? */ if (end_of_file()) break; if (n == RF_INCLUDE) { getarg(inc_fn); push_include(inc_fn); continue; } else if (n == RF_SET) { rule_set = getnbr(255); if (rule_set == RF_SYMBOL) { strcpy(mri->ri_Name, symbol_table[st_index].id); symbol_table[st_index].value = 1; /* Suppress 'undefined' error msg */ } else sprintf(mri->ri_Name, "%d", rule_set); kind = RF_RULES; continue; } else if (n == RF_RULES) { kind = RF_RULES; continue; } else if (n == RF_FORMAT) { for (a = 0; a != LASTATTRIB+1; ++a) ms->format[a] = ms->required[a] = 0; for (a = 0; ; ) { n = getnbr(255); if (n < 0 || n > LASTATTRIB) { sprintf(err_msg,"Attribute %d not allowed in format",n); p_error(err_msg); } else { ms->format[a] = n; ms->required[n] = 1; ms->separator[a] = " "; /* Default */ } if (ic == ';' || end_of_file()) break; for (;;) { if (end_of_file() || !isspace(ic)) break; nextchar(); } if (ic == ';' || end_of_file()) break; if (!isalnum(ic)) { /* User-specified separator */ if (ic == '\"') { nextchar(); /* Opening quote */ for (sp = sbuf; ; ) { if (end_of_file()) { p_error("Missing \""); break; } else if (ic == '\"' && ibp[-2] != '\\') break; else *sp++ = ic; if (*ibp == '#') { /* Allow # in string */ lic = ic; ic = *ibp++; } else nextchar(); } nextchar(); } else { sp = sbuf; *sp++ = ' '; for (;;) { if (isspace(ic)) break; *sp++ = ic; nextchar(); } *sp++ = ' '; } *sp = '\0'; ms->separator[a] = gcstring(sbuf, &len); } ++a; if (ic == ';' || end_of_file()) break; } if (list) { printf("Format: "); for (n = ms->format[a = 0]; ; ) { for (b = 1; b <= SZ_ATTRIBS && attribs[b].index != n; ++b) ; if (b <= SZ_ATTRIBS) fprintf(stdout,attribs[b].name); else fprintf(stdout,"attr*%u", n); /* Unknown attribute */ if ((n = ms->format[a+1]) == 0) { /* Last attribute */ if (strcmp(ms->separator[a]," ") != 0) printf(ms->separator[a]); /* No trailing blank */ break; } printf(ms->separator[a++]); } printf("\n"); } continue; } else if (n == RF_STATS) { ms->statsreqd = 1; /* Collect statistics */ continue; } labels = -1; /* Make chain of labels for this rule */ while (n == RF_SYMBOL) { /* Allow multiple labels */ if (pass == 1) { if (symbol_table[st_index].value == 0) { symbol_table[st_index].value = kind; symbol_table[st_index].target = nrules+1; /* (kind == RF_RULES ? nrules : nactions) + 1; !! */ if (verbose) printf("line %d: %s is %s %d\n", rule_line, symbol_table[st_index].id, kind == RF_RULES ? "rule" : "?????", symbol_table[st_index].target); } else { sprintf(err_msg,"Duplicate label %s", symbol_table[st_index].id); p_error(err_msg); } } symbol_table[st_index].action = labels; /* Remember the labels */ labels = st_index; nextchar(); n = getnbr(255); } if (kind == RF_RULES) { ri.RuleSelector = n; /* Attribute nbr */ seltype = toktype; len = toktype == TOK_ATTRIB ? toklen : 1; getaddress(ri.RuleMask,len, RULE_ADDR_LEN); if (end_of_file()) break; getaddress(ri.RuleMatchedValue,len, RULE_ADDR_LEN); if (end_of_file()) break; ri.RuleAction = getnbr(255); if (toktype != TOK_ACTION && !(toktype == TOK_INT && ri.RuleAction >= RA_IGNORE && ri.RuleAction <= RA_POPTOACT )) p_error("Rule action expected"); if (end_of_file()) break; ri.RuleJumpIndex = getnbr(32767); /* NB, 22 Oct 93 */ if ((toktype != TOK_WORD || ri.RuleJumpIndex != RF_NEXT) && toktype != TOK_INT && toktype != TOK_SYMBOL) p_error("Label or rule number expected"); if (ri.RuleJumpIndex == RF_NEXT) ri.RuleJumpIndex = nrules+2; /* nrules not incremented yet! */ if (ri.RuleAction == RA_SUCCEED) { ri.RuleAction = ri.RuleJumpIndex == 0 ? RA_IGNORE : RA_GOTOACT; } cf = cfa = 0; while (labels >= 0) { /* Set action in rule's label entries */ n = symbol_table[labels].action; symbol_table[labels].action = ri.RuleAction; if (pass == 2) { if (symbol_table[labels].comefrom) ++cf; else if (symbol_table[labels].comefromAct) ++cfa; if (testing) fprintf(stderr, "LABEL: %s, line=%d cf=%d, cfa=%d\n", symbol_table[labels].id, rule_line, cf, cfa); } labels = n; } if (ri.RuleAction == RA_AGGREGATE) p_error( "Aggregate action no longer available: use Count instead"); else if (ri.RuleAction == RA_TALLY) p_error( "Tally action no longer available: use Count instead"); else if (ri.RuleAction == RA_ASSIGN || ri.RuleAction == RA_ASSIGNACT) { if (ri.RuleSelector < FTV1 || ri.RuleSelector > FTV5) p_error("Assign target (first field of rule) must be v1..v5"); if (ri.RuleMatchedValue[1] != 0 || ri.RuleMatchedValue[0] < 1 || ri.RuleMatchedValue[0] > LASTATTRIB) { sprintf(err_msg,"Assign value %d not an attribute number", ri.RuleMatchedValue[0]); p_error(err_msg); } } else if (seltype != TOK_ATTRIB && (ri.RuleSelector < 0 || ri.RuleSelector > LASTATTRIB)) p_error("Selector value should be an attribute"); if (toktype == TOK_SYMBOL) { ri.RuleJumpIndex = symbol_table[st_index].target; if (pass == 1) { if (action_type[ri.RuleAction] == TR_TO) ++symbol_table[st_index].comefrom; else if (action_type[ri.RuleAction] == TR_ACT) ++symbol_table[st_index].comefromAct; else p_error("Symbol must be target of Goto or GotoAct"); if (testing) fprintf(stderr, "SYMBOL: %s, line=%d cf=%d, cfa=%d\n", symbol_table[st_index].id, rule_line, symbol_table[st_index].comefrom, symbol_table[st_index].comefromAct); } } if (pass == 2) { if (ri.RuleAction == RA_GOSUB || ri.RuleAction == RA_GOSUBACT) gosub_rule = 1; else if (ri.RuleSelector == 0) /* Null selector */ gosub_rule = last_gosub_rule; else gosub_rule = 0; only_gotoAct = 0; #if RULETEST_DEBUG printf("-- rule_line=%d, nrules=%d, cf=%d, cfa=%d, last_gosub_rule=%d", rule_line, nrules, cf,cfa, last_gosub_rule); #endif if (!cf) { /* There are no Gotos to this rule */ if (last_ri.RuleSelector == 0) { /* Null selector */ switch (action_type[last_ri.RuleAction]) { case TR_FIN: if (!cfa && nrules != 0 && !last_gosub_rule) p_warn("Rule can't be executed (null+fin)"); only_gotoAct = 1; break; case TR_ACT: if (last_ri.RuleJumpIndex != nrules+1 /* Next */ && !cfa && nrules != 0 && !last_gosub_rule) p_warn("Rule can't be executed (null+Act)"); only_gotoAct = 1; break; case TR_TO: if (last_ri.RuleJumpIndex == nrules+1) /* Next */ only_gotoAct = 0; else if (!cfa && nrules != 0 && !last_gosub_rule) { p_warn("Rule can't be executed (null+to)"); only_gotoAct = 1; } else only_gotoAct = 1; break; } } else { /* Non-null selector */ switch (action_type[last_ri.RuleAction]) { case TR_FIN: if (!cfa && nrules == 0 && !last_gosub_rule) p_warn("Rule can't be executed (sel+fin)"); only_gotoAct = 1; case TR_ACT: only_gotoAct = last_only_gotoAct; break; case TR_TO: if (last_only_gotoAct) only_gotoAct = last_ri.RuleJumpIndex != nrules+1; /* Next */ else only_gotoAct = 0; break; } } } #if RULETEST_DEBUG printf(", only_gotoAct=%d, last_only_gotoAct=%d\n", only_gotoAct, last_only_gotoAct); #endif if (nrules != 0) { /* Check flow-in to non-test actions */ switch (ri.RuleAction) { case RA_COUNTPKT: case RA_ASSIGN: case RA_ASSIGNACT: case RA_PUSHPKTTO: case RA_PUSHPKTTOACT: if (!only_gotoAct) { if (!cf) p_error("Possible flow into rule: must GotoAct"); else p_error("Possible Goto to this rule: must GotoAct"); } break; } } #ifdef NEW_ATR if (DISTRIB_ATTRIB(ri.RuleSelector)) { switch (ri.RuleAction) { case RA_COUNT: case RA_PUSHTO: case RA_PUSHTOACT: p_error("Must pushPkt distribution-valued attributes"); break; } } #endif if (ri.RuleJumpIndex != 0) { switch (ri.RuleAction) { /* Check target of goto */ case RA_PUSHTO: case RA_PUSHPKTTO: case RA_GOSUB: case RA_GOTO: if (toktype == TOK_SYMBOL) { n = symbol_table[st_index].action; if (n == RA_ASSIGN || n == RA_ASSIGNACT) p_error("Must goto Action of an Assign rule"); if (n == RA_PUSHPKTTO || n ==RA_PUSHPKTTOACT) p_error("Must goto Action of a PushPkt rule"); } break; } switch (ri.RuleAction) { case RA_COUNT: case RA_COUNTPKT: p_error("Index no longer used by count: zero required"); break; case RA_FAIL: case RA_IGNORE: p_error("Zero index required"); break; case RA_PUSHTO: case RA_PUSHTOACT: case RA_PUSHPKTTO: case RA_PUSHPKTTOACT: case RA_GOTO: case RA_GOTOACT: case RA_GOSUB: case RA_GOSUBACT: if (toktype == TOK_SYMBOL) { if (symbol_table[st_index].value != RF_RULES) p_error("Rule index required"); if (ri.RuleJumpIndex == 0) { sprintf(err_msg,"Undeclared label %s", symbol_table[st_index].id); p_error(err_msg); } } else if (toktype == TOK_INT && (ri.RuleJumpIndex < 1 || ri.RuleJumpIndex > ms->nrules)) p_error("Rule index required"); break; case RA_RETURN: if (toktype != TOK_INT || ri.RuleJumpIndex < 1 || ri.RuleJumpIndex > 200) p_error("Gosub offset must be > 0"); break; } } else { /* JumpIndex == 0 */ switch (ri.RuleAction) { case RA_PUSHTO: case RA_PUSHTOACT: case RA_PUSHPKTTO: case RA_PUSHPKTTOACT: case RA_GOTO: case RA_GOTOACT: case RA_GOSUB: case RA_GOSUBACT: p_error("Target of jump can't be zero"); break; case RA_RETURN: p_error("Gosub offset must be > 0"); break; } } } if (ri.RuleAction == RA_COUNT || ri.RuleAction == RA_COUNTPKT) { ri.RuleJumpIndex = ++ncounts; } if (end_of_file()) break; ri.RuleNbr = ++nrules; if (list && verbose) { printf("Rule %d,%d: %d & ", rule_set,nrules,ri.RuleSelector); printruleaddress(stdout, ri.RuleMask); printf(" = "); printruleaddress(stdout, ri.RuleMatchedValue); printf(": %d, %d\n", ri.RuleAction,ri.RuleJumpIndex); } if (doset) add_rule(ms,&ri); /* Add rule to meter's rule table */ memcpy(&last_ri, &ri, sizeof(ri)); last_only_gotoAct = only_gotoAct; last_gosub_rule = gosub_rule; } } if (doset) add_rule(ms, NULL); /* Flush download buffer */ fclose(rfp); for (n = 0; n != st_top; ++n) { if (symbol_table[n].type == TOK_SYMBOL && symbol_table[n].value == 0) { printf(">>> Symbol %s is undefined\n", symbol_table[n].id); ++rferrors; } } if (rule_set == 0) { printf(">>> No SET statement in rule file %s\n", rfname); ++rferrors; return 0; } if (rferrors == 0) { ms->ruleset = rule_set; ms->nrules = nrules; ms->ncounts = ncounts; return 1; /* Succeed */ } return 0; /* Fail */ } int download_ruleset(struct meter_status *ms, int standby) { struct meter_rule_info *mri; mri = standby ? &ms->s_ruleset : &ms->c_ruleset; if (ms->MIBver == 4) { /* 'new' proposed standard MIB */ if (ruleset_util(ms,RU_INIT, mri)) { /* Create the table row */ scan_rulefile(ms,1,0,standby); /* 1 => download rules */ log_msg(LOG_INFO, FALSE, "loaded %d rules from %s to meter %s\n", mri->ri_Size, mri->filename, ms->name); ruleset_util(ms,RU_READY, mri); /* Set RulesReady */ } else { /* Don't leave a 'skeleton' row! */ ruleset_util(ms, RU_DESTROY, mri); return 0; } } else { /* 'old' NeTraMet v3 MIB */ if (set_rule_info(ms,0)) { /* Set rule table size */ scan_rulefile(ms,1,0,standby); /* 1 => download rules */ } } return 1; } int parse_rulefile(struct meter_status *ms, int list, int syntax, int standby, int restart) { int using_standby; MIBver = ms->MIBver; init_symbol_table(); /* Must re-initialise for each meter */ #if LINEAR_SEARCH st_top = 0; #endif pass = 1; if (testing) fprintf(stderr, "parse_rf(): standby=%d, standby rf %s, current rf %s\n", standby, ms->s_ruleset.filename, ms->c_ruleset.filename); if (scan_rulefile(ms,0,0,standby)) { /* No errors so far */ pass = 2; if (scan_rulefile(ms,0,list,standby)) { /* Still no errors */ pass = 3; if (ms->MIBver == 3) { if (standby) { /* Specifying standby rule set */ if (ms->ruleset > 1 && /* It's a user-specified set */ ms->nrules != 0) { /* Rules were specified */ ms->s_ruleset.ri_Index = ms->ruleset; if (syntax) return 1; if (ms->ruleset == ms->CurrentRuleSet) { /* Ask meter to use default rule set */ ms->c_ruleset.ri_Index = 1; set_rule_info(ms,1); ms->CurrentRuleSet = 1; /* Now using default rule set */ if (ms->download_level == 0 || (ms->download_level == 1 && restart)) { download_ruleset(ms, standby); } if (ms->c_ruleset.filename[0] == '\0') { /* No rulefile specified */ ms->c_ruleset.ri_Index = ms->ruleset; set_rule_info(ms,1); /* Use new standby rule set */ ms->CurrentRuleSet = ms->ruleset; } } else { /* Target rule set not in use */ if (ms->download_level == 0 || (ms->download_level == 1 && restart)) { download_ruleset(ms, standby); } } } set_rule_info(ms,2); /* Set the standby rule set */ ms->StandbyRuleSet = ms->s_ruleset.ri_Index; } else { /* Specifying current rule set */ if (testing) fprintf(stderr, "Pass 3: ruleset=%d, nrules=%d, CurrentRuleSet=%d, " "download_level=%d, restart=%d\n", ms->ruleset,ms->nrules, ms->CurrentRuleSet, ms->download_level, restart); if (ms->nrules != 0) { /* Rules were specified */ ms->c_ruleset.ri_Index = ms->ruleset; if (syntax) return 1; if (ms->ruleset == ms->CurrentRuleSet) { ms->c_ruleset.ri_Index = 1; /* Ask meter to use default rule set */ set_rule_info(ms,1); ms->CurrentRuleSet = 1; /* Now using default rule set */ } ms->c_ruleset.ri_Index = ms->ruleset; if (ms->download_level == 0 || (ms->download_level == 1 && restart)) { download_ruleset(ms, 0); /* 0 => current */ } } ms->c_ruleset.ri_Index = ms->ruleset; if (ms->c_ruleset.ri_Index != ms->CurrentRuleSet) { set_rule_info(ms,1); /* Start using specified rule set */ ms->CurrentRuleSet = ms->c_ruleset.ri_Index; } } } else { /* MIBver == 4 */ if (testing) fprintf(stderr, "Pass 3: standby=%d, ruleset=%d, nrules=%d," "download_level=%d, restart=%d\n", standby, ms->ruleset,ms->nrules, ms->download_level, restart); if (syntax) return 1; if (!ms->use_meter_rows) { if (standby) { /* Specifying standby rule set */ if (ms->nrules != 0) { /* Rules were specified */ if (download_ruleset(ms, 1)) { /* 1 => standby */ if (ms->mi_Index == 0) task_util(ms, TU_INIT); task_util(ms, TU_STANDBY); } else return 0; } } else { /* Specifying current rule set */ if (ms->nrules != 0) { /* Rules were specified */ if (download_ruleset(ms, 0)) { /* 0 => current */ if (ms->mi_Index == 0) task_util(ms, TU_INIT); task_util(ms, TU_CURRENT); } else return 0; } } } } } } return 1; }