/* 1517, Thu 8 Jun 00 SRL_SCAN.C: Scanner for SRL compiler Copyright (C) 1998-2002 by Nevil Brownlee, CAIDA | University of Auckland */ /* * $Log: srl_scan.c,v $ * Revision 1.1.1.2.2.11 2002/02/23 01:57:43 nevil * Moving srl examples to examples/ directory. Modified examples/Makefile.in * * Revision 1.1.1.2.2.6 2000/08/08 19:45:01 nevil * 44b8 release * * Revision 1.1.1.2.2.4 2000/06/06 03:38:34 nevil * Combine NEW_ATR with TCP_ATR, various bug fixes * * Revision 1.1.1.2.2.1 2000/01/12 02:57:16 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 1999/10/03 21:06:35 nevil * *** empty log message *** * * Revision 1.1.1.1.2.10 1999/09/22 05:34:12 nevil * Implement command-line defines * - Initialise scanner in init_symbol_table() * - Add get_command_define() to scanner. This dummies up a define * statement then calls push_include to invoke it * - Call get_command_define from main when we see a -D option * * Revision 1.1.1.1.2.9 1999/09/14 00:50:44 nevil * 4.3 Release * * Revision 1.1.1.1.2.8 1999/05/18 03:36:30 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.7 1999/04/26 05:20:59 nevil * -Allow redeclaration of 'built-ins,' i.e. well-known ports, address * families and transport types. A warning is given telling the * user what was redclared. * -Fix bug in checking of subroutine calls. If a call appears before * the subroutine declaration, it must have an integer label matching * the highest one in the subroutine. This is because the compiler * doesn't emit dummy rules (to allow for returns) until after the * declaration. * -Warn user that NeMaC doesn't handle return labels > 200. * -Warn user that NeMaC requires one SET and one FORMAT statement, * and that every program should have at least one COUNT statement. * * Revision 1.1.1.1.2.6 1999/04/09 03:49:01 nevil * Implemented IPv6 addresses for SRL * -D define V6 to enable the v6 code * Added IPv4 and IPv6 as address families (IP => IPv4) * Added get_v6address ro srl_scan * v6err() routine to print v6 address errors * V6DEBUG turns on v6 parser debugging * * Revision 1.1.1.1.2.5 1999/03/31 03:01:52 nevil * Added better error messages (and error recovery): * Attempt to redefine reserved word, protocol, port, address family * Char constants must have just one character * Corrected err_msg() to avoid msg buffer overflow when printing * an error message from within the body of a define. * Improved error reovery for invald tokens in subroutine declarations * and call statements. * * Revision 1.1.1.1.2.4 1999/01/28 03:12:10 nevil * Mis-spelt attribute names are now correctly reported as errors * * Revision 1.1.1.1.2.3 1999/01/27 04:26:18 nevil * Minor corrections to fix compiler warnings * * Revision 1.1.1.1.2.2 1999/01/08 01:38:43 nevil * Distribution file for 4.3b7 * * Revision 1.1.1.1.2.1 1998/11/19 02:13:26 nevil * Allow mask_from_width() to accept zero width * * Revision 1.1.1.1 1998/11/16 03:57:33 nevil * Import of NeTraMet 4.3b3 * * Revision 1.1.1.1.2.2 1998/11/12 23:23:14 nevil * Mask and value weren't being set correctly for distribution-valued * attributes. Fixed call to getaddress() to specify DIST_PARAM_LENGTH. * * Revision 1.1.1.1.2.1 1998/11/11 23:14:49 nevil * Only include malloc.h if we HAVE_MALLOC_H * * Revision 1.1.1.1 1998/10/28 20:31:34 nevil * Import of NeTraMet 4.3b1 * * Revision 1.1.2.1 1998/10/22 21:40:41 nevil * Moved srl from src/manager to its own subdirectory * * Revision 1.1.3.2 1998/10/18 23:44:15 nevil * Added Nicolai's patches, some 'tidying up' of the source * * Revision 1.1.3.1 1998/10/13 02:48:29 nevil * Import of Nicolai's 4.2.2 * * Revision 1.1.1.1 1998/08/24 12:09:29 nguba * NetraMet 4.2 Original Distribution * * Revision 1.2 1998/07/21 00:43:57 rtfm * Change attrib numbers for 'New Attribs' I-D * First release version of SRL */ #if HAVE_CONFIG_H #include #endif #define CHAR_TRACE 0 #define V6DEBUG 0 /* 1 to print v6 addrs, 2 for debugging */ #include #include #include #include #if HAVE_MALLOC_H # include #endif #include #include #include #define RTFMEXT #include "rtfm_atr.h" #include "srl.h" unsigned char *strmov(unsigned char *d, unsigned char *s) { while (*s != '\0') *d++ = *s++; return d; } char *gnbr(unsigned long *n, char *s) /* Get nbr from 's', return updated 's' */ { unsigned long v = 0; unsigned b = 10, d; 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 *c_esc_char(unsigned long *n, char *s) { static char escin[] = { 'b', 'f', 'n', 'r', 't', 'v','\\','\'','\"','\?', 0 }; static char escout[] ={ '\b','\f','\n','\r','\t','\v','\\','\'','\"','\?', 0 }; unsigned long c; int j; c = *s; if (c == '0' || c == 'x' || c == 'X') { /* Octal or hex nbr */ s = gnbr(&c,s); *n = c; } else if (isdigit(c)) { /* Octal number */ --s; *s = '0'; /* Make gnbr use base 8 */ s = gnbr(&c,s); *n = c; } else { j = 0; do { if (c == escin[j]) break; } while (escin[++j] != 0); *n = escout[j]; ++s; } return s; } #if 0 /* Not used char *gcstring(char *s, int *len) /* Get string from s */ { unsigned long c; char sbuf[80], *t = sbuf, *rp; while (*s) { if (*s == '\\') { s = c_esc_char(&c, ++s); *t++ = c; } else *t++ = *s++; } *t = '\0'; *len = t-sbuf; rp = (char *)malloc(*len+1); strcpy(rp,sbuf); return rp; } #endif char *fmt_time(time_t *t) { static char ftb[32]; char *ts = ctime(t); 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'; return ftb; } static struct pt_node *free_nodes = NULL, *node_blk; static int nf_nodes = 0; struct pt_node *alloc_node(void) /* Allocate a node */ { struct pt_node *q; if (free_nodes != NULL) { q = free_nodes; free_nodes = free_nodes->left; } else { if (nf_nodes == 0) { node_blk = (struct pt_node *) malloc(sizeof(struct pt_node)*PTNBLKSIZE); if (node_blk == NULL) { printf("No memory for new pt nodes!"); return NULL; } nf_nodes = PTNBLKSIZE-1; } else { ++node_blk; --nf_nodes; } q = node_blk; } memset(q, 0, sizeof(struct pt_node)); return q; } void free_node(struct pt_node *b) /* Return b to free list */ { if (b == NULL) return; /* Not really a node! */ b->left = free_nodes; free_nodes = b; } unsigned char *sprintvalue(unsigned char *s, unsigned char *v) { int j, k; unsigned char b[50]; sprintf(b, "%u", v[0]); s = strmov(s, b); for (k = RULE_ADDR_LEN-1; k != 1; --k) if (v[k] != 0) break; /* Need min 2 bytes for 10.0 et al */ for (j = 1; j <= k; ++j) { sprintf(b, ".%u", v[j]); s = strmov(s,b); } return s; } unsigned char *sprintvalmsk(unsigned char *s, struct pt_node *n) { s = sprintvalue(s, n->d.operand.value); s = strmov(s, (unsigned char *)" & "); s = sprintvalue(s, n->d.operand.mask); *s = '\0'; return s; } void printvalue(unsigned char *v) { int j, k; printf("%u", v[0]); for (k = RULE_ADDR_LEN-1; k != 0; --k) if (v[k] != 0) break; for (j = 1; j <= k; ++j) printf(".%u", v[j]); } void free_pt(struct pt_node *n) { if (n == NULL) return; if (n->type == NT_OPERAND) free_node(n); else if (n->type == NT_BINOP) { free_pt(n->left); free_pt(n->right); free_node(n); } } int set_grpsz_pt(struct pt_node *n) { int r, lor, ror; if (n == NULL) return 0; if (n->type == NT_OPERAND) r = 1; else if (n->type == NT_BINOP) { lor = set_grpsz_pt(n->left); ror = set_grpsz_pt(n->right); if (n->d.binop.operator == SC_LOR || n->d.binop.operator == SC_SAMEOR) { if (lor == 0 || ror == 0) r = 0; else r = lor+ror; } else if (n->d.binop.operator == SC_LAND) r = 0; } return n->grpsz = r; } int set_mxd_pt(struct pt_node *n) { int r, ld, rd; if (n == NULL) return 0; if (n->type == NT_OPERAND) r = 1; else if (n->type == NT_BINOP) { ld = set_mxd_pt(n->left); rd = set_mxd_pt(n->right); if (n->d.binop.operator == SC_LOR || n->d.binop.operator == SC_SAMEOR) r = ld > rd ? ld : rd; else if (n->d.binop.operator == SC_LAND) r = ld+rd; } return n->maxdepth = r; } void print_pt(struct pt_node *n, int depth, char *msg) { int j, r; if (n == NULL) return; if (n->type == NT_OPERAND) { for (j = 0; j != depth; ++j) printf(" "); printf("%s %d == ", msg, n->d.operand.attrib); printvalue(n->d.operand.value); printf(" & "); printvalue(n->d.operand.mask); printf("\n"); } else if (n->type == NT_BINOP) { for (j = 0; j != depth; ++j) printf(" "); if (n->d.binop.operator == SC_LOR) printf("|| mxd=%d, grpsz=%d\n", n->maxdepth, n->grpsz); else if (n->d.binop.operator == SC_SAMEOR) printf("() mxd=%d, grpsz=%d\n", n->maxdepth, n->grpsz); else if (n->d.binop.operator == SC_LAND) printf("&& mxd=%d, grpsz=%d\n", n->maxdepth, n->grpsz); print_pt(n->left, depth+1, " L"); print_pt(n->right, depth+1, " R"); } } void mask_from_width(unsigned char *m, int w) { int j, x, a; memset(m,0,RULE_ADDR_LEN); if (w > RULE_ADDR_LEN*8) { err_msg(ET_ERR, "Width > %d", RULE_ADDR_LEN*8); return; } if (w == 0) return; for (x = 0, j = 0; ; ) { for (a = 0x80; ; ) { m[j] |= a; if (++x == w) return; a >>= 1; if (a == 0) break; } ++j; } } #if 0 /* Not used */ int width_from_mask(unsigned char *m) { int w, j, a; for (w = RULE_ADDR_LEN*8, j = RULE_ADDR_LEN-1; ; ) { for (a = 0x01; ; ) { if (m[j] & a) return w; a = (a << 1) & 0xFF; --w; if (a == 0) break; } if (--j < 0) return 0; } } #endif void err_msg(int err_type, char *fmt, ...) { char msg[16+7+sizeof(inbuf)+1]; int position, margin, i; struct incl_ent *iep; va_list ap; if (!iblisted) { printf("%16s %4d: %s", scan_sfname,line_nbr,inbuf); iblisted = 1; } if (err_type == ET_NULL) return; if (!in_define) position = ibp - inbuf; else { for (i = incl_depth-1; i >= 0; --i) { iep = &incl_stack[i]; if (!iep->in_define) break; } position = iep->bp - inbuf; } i = strlen(scan_sfname); if (i < 16) i = 16; margin = i + 7 + position - (toklen+1); if (margin > sizeof(msg)-(toklen+1)) margin = sizeof(msg)-(toklen+1); /* Don't overrun msg buffer */ memset(msg,' ',margin); memset(&msg[margin],'^',toklen); msg[margin+toklen] = '\0'; printf("%s\n", msg); if (err_type == ET_WARN) { /* 12345678901234567890123 */ printf(" WARNING >>>> "); ++sfwarnings; } else { printf(" ERROR >>>> "); ++sferrors; } va_start(ap, fmt); vprintf(fmt, ap); printf("\n"); } int lookup(char *id) /* Return 0 if id was not in id[] */ { /* Otherwise returns 1, id_index, toktype */ int id_len, j; unsigned int hash; struct ident *lip, *ip; hash = id_len = strlen(id); for (j = 0; j != id_len; ++j) hash += id[j]; id_index = hash & IDTHASHMASK; ip = &id_table[id_index]; lip = NULL; if (ip->id[0] != 0) { /* At least one entry for this hash */ if (strcmp(ip->id,id) == 0) { toktype = ip->type; return 1; } else { for (;;) { lip = ip; if (lip->next == 0) break; /* End of chain */ ip = &id_table[id_index = lip->next]; if (strcmp(ip->id,id) == 0) { toktype = ip->type; return 1; } } } } /* Not there, put it in */ if (lip != NULL) { /* Add to hash chain */ if (id_top == IDTSIZE) { err_msg(ET_ERR, "More than %d identifiers",IDTSIZE); } else { /* Add new identifier */ id_index = id_top++; lip->next = id_index; ip = &id_table[id_index]; } } memset(ip, 0, sizeof(struct ident)); strncpy(ip->id, id, id_len); ip->id[id_len] = '\0'; return 0; /* Not already in id_table, now added */ } void start_st_block(char *block_name) { memset(&st[st_top],0,sizeof(struct symbol)); st[st_top].symtype = ST_BLOCK; st[st_top].prev = last_block_ix; strcpy(st[st_top].name, block_name); last_block_ix = st_top; ++st_top; } void add_symbol(int symtype) { memset(&st[st_top],0,sizeof(struct symbol)); st[st_top].symtype = symtype; st[st_top].idx = id_index; if (id_table[id_index].stx) { /* Already a symbol with this id */ st[st_top].prev = id_table[id_index].stx; } id_table[id_index].stx = st_top; ++st_top; } void add_argument(int symtype, int reg, int attrib) { memset(&st[st_top],0,sizeof(struct symbol)); st[st_top].symtype = symtype; st[st_top].d.arg.reg = reg; st[st_top].d.arg.attrib = attrib; ++st_top; } void release_symbol(int stx) /* Release id from st[stx] */ { int idx = st[stx].idx; if (st[stx].symtype == ST_DEFINE) free(st[stx].d.def_str); id_table[idx].stx = st[stx].prev; if (st[stx].prev == 0) id_table[idx].type = TOK_UNUSED; /* Leave it in hash chain */ } void clear_st_block(void) { int idx; for ( ; st_top != last_block_ix+1; ) release_symbol(--st_top); last_block_ix = st[--st_top].prev; idx = st[st_top].idx; } void clear_st_subroutine(int stx) { int j; struct symbol *sp, *new_sp; int inner_stx, new_st_top, np; for (inner_stx = 0, j = st_top ; j != stx+1; ) { sp = &st[--j]; if (sp->symtype != ST_SUBROUTINE || sp->prev != 0 && st[sp->prev].symtype == ST_SUBROUTINE) release_symbol(j); else inner_stx = j; /* Lowest 'new' subroutine */ } sp = &st[stx]; if (sp->prev == 0 || st[sp->prev].symtype != ST_SUBROUTINE) new_st_top = stx+1 + st[stx].d.sub.n_params + 1; else { /* Subroutine already declared */ release_symbol(stx); new_st_top = stx; } if (inner_stx != 0) { /* Move subroutine call entries down */ for (j = inner_stx; j < st_top; ) { sp = &st[j]; if (sp->symtype == ST_SUBROUTINE && sp->prev == 0 || st[sp->prev].symtype != ST_SUBROUTINE) { new_sp = &st[new_st_top]; memmove(new_sp, sp, sizeof(struct symbol)); /* Subroutine */ id_table[sp->idx].stx = new_st_top; new_sp->prev = 0; memmove(++new_sp, ++sp, sizeof(struct symbol)); /* Block mark */ np = new_sp->d.sub.n_params; while (np != 0) { memmove(++new_sp, ++sp, sizeof(struct symbol)); --np; } new_st_top += 2+np; j += 2+np; } else ++j; } } st_top = new_st_top; last_block_ix = st[last_block_ix].prev; } void dump_symbol_table() { int j; struct ident *ip; struct symbol *sp; printf("Symbol table =========================\n"); printf("last_block_ix=%d, st_top=%d\n", last_block_ix, st_top); for (j = st_top-1; j >= 0; --j) { sp = &st[j]; printf("%3d, %15s: symtype=%s", j, id_table[sp->idx].id, sym_types[sp->symtype]); if (sp->symtype == ST_DEFINE) printf(", define=%s", sp->d.def_str); if (sp->symtype == ST_SUBROUTINE) printf(", params(%d,%d), returns=%d", sp->d.sub.first_param, sp->d.sub.n_params, sp->d.sub.n_returns); if (sp->symtype == ST_ADDRESS || sp->symtype == ST_VARIABLE) printf(", reg=%d, attrib=%d", sp->d.arg.reg, sp->d.arg.attrib); if (sp->name != NULL) printf(", name=%s", sp->name); printf("\n"); } if (verbose > 2) { printf("Identifier table ---------------------\n"); for (j = 0; j != id_top; ++j) { ip = &id_table[j]; if (ip->id[0] != 0) { printf("%3d, %5d: %s type=%s, subtype=%d, stx=%d\n", j, ip->next, ip->id, tok_types[ip->type],ip->subtype, ip->stx); } } } } void add_ident(char *id, int type, int subtype) { struct ident *ip; lookup(id); ip = &id_table[id_index]; ip->type = type; ip->subtype = subtype; } void init_symbol_table() { int j; for (j = 0; j <= LASTATTRIB; ++j) attr_ix[j] = 0; for (j = 0; j != SZ_ATTRIBS; ++j) attr_ix[attribs[j].index] = j; id_top = IDTHASHBASE; for (j = 0; j != IDTHASHBASE; ++j) id_table[j].id[0] = '\0'; last_block_ix = 0; add_ident("include", TOK_RSVWD, RW_INCLUDE); /* Pragmas */ add_ident("optimise", TOK_RSVWD, RW_OPTIMISE); add_ident("optimize", TOK_RSVWD, RW_OPTIMISE); add_ident("set", TOK_RSVWD, RW_SET); add_ident("statistics", TOK_RSVWD, RW_STATS); add_ident("format", TOK_RSVWD, RW_FORMAT); add_ident("address", TOK_RSVWD, RW_ADDRESS); /* Reserved words */ add_ident("call", TOK_RSVWD, RW_CALL); add_ident("count", TOK_RSVWD, RW_COUNT); add_ident("define", TOK_RSVWD, RW_DEFINE); add_ident("else", TOK_RSVWD, RW_ELSE); add_ident("endcall", TOK_RSVWD, RW_ENDCALL); add_ident("endsub", TOK_RSVWD, RW_ENDSUB); add_ident("exit", TOK_RSVWD, RW_EXIT); add_ident("if", TOK_RSVWD, RW_IF); add_ident("ignore", TOK_RSVWD, RW_IGNORE); add_ident("nomatch", TOK_RSVWD, RW_NOMATCH); add_ident("return", TOK_RSVWD, RW_RETURN); add_ident("save", TOK_RSVWD, RW_SAVE); add_ident("store", TOK_RSVWD, RW_STORE); add_ident("subroutine", TOK_RSVWD, RW_SUBROUTINE); add_ident("variable", TOK_RSVWD, RW_VARIABLE); for (j = 0; j != SZ_ATTRIBS; ++j) { add_ident(attribs[j].name, TOK_ATTRIB, attribs[j].index); } add_ident("dummy", TOK_AFTYPE, AT_DUMMY); /* Address families */ add_ident("ip", TOK_AFTYPE, AT_IP4); add_ident("ipv4", TOK_AFTYPE, AT_IP4); add_ident("ipv6", TOK_AFTYPE, AT_IP6); add_ident("ipx", TOK_AFTYPE, AT_NOVELL); add_ident("novell", TOK_AFTYPE, AT_NOVELL); add_ident("decnet", TOK_AFTYPE, AT_DECNET); add_ident("ethertalk", TOK_AFTYPE, AT_ETHERTALK); add_ident("clns", TOK_AFTYPE, AT_CLNS); add_ident("other", TOK_AFTYPE, AT_OTHER); add_ident("icmp", TOK_TRANSPR, PT_ICMP); /* Transport-layer protocols */ add_ident("tcp", TOK_TRANSPR, PT_TCP); add_ident("udp", TOK_TRANSPR, PT_UDP); add_ident("ospf", TOK_TRANSPR, PT_OSPF); add_ident("ftpdata", TOK_WKP, WNP_FTPDATA); /* IP well-known ports */ add_ident("ftp", TOK_WKP, WNP_FTP); add_ident("http", TOK_WKP, WNP_WWW); add_ident("telnet", TOK_WKP, WNP_TELNET); add_ident("smtp", TOK_WKP, WNP_SMTP); add_ident("domain", TOK_WKP, WNP_DOMAIN); add_ident("nntp", TOK_WKP, WNP_NNTP); add_ident("ntp", TOK_WKP, WNP_NTP); add_ident("snmp", TOK_WKP, WNP_SNMP); add_ident("gopher", TOK_WKP, WNP_GOPHER); add_ident("www", TOK_WKP, WNP_WWW); last_block_ix = st_top = 0; start_st_block("<>"); sfwarnings = sferrors = line_nbr = 0; /* Initialise scanner */ incl_depth = in_define = 0; ic = '\n'; lic = ' '; } static unsigned char sfdirectory[FNAME_LN]; int parse_open(unsigned char *fn) /* Open file and initialise parser */ { unsigned char *fdp; if ((sfp = fopen(fn, "r")) == NULL) { sferrors = 1; return 0; } fdp = strmov(sfdirectory,fn); /* Remember source directory */ for (;;) { if (fdp == sfdirectory || *fdp == '/') break; --fdp; } *fdp = '\0'; strcpy(scan_sfname,fn); /* Remember rule file's name */ return 1; } void push_include(int include, char *ifp) { char incfn[FNAME_LN]; struct incl_ent *iep; if (incl_depth == MXINCL) { err_msg(ET_ERR, "Includes/defines nested too deep"); return; } iep = &incl_stack[incl_depth]; iep->fp = sfp; if (include) { sprintf(incfn, "%s/%s", sfdirectory, ifp); if ((sfp = fopen(incfn, "r")) == NULL) { if ((sfp = fopen(ifp, "r")) == NULL) { err_msg(ET_ERR, "Couldn't open include file"); sfp = iep->fp; return; } } } strcpy(iep->buf,inbuf); iep->bp = ibp; iep->in_define = in_define; iep->line_nbr = line_nbr; iep->iblisted = iblisted; iep->lic = lic; iep->ic = ic; strcpy(iep->sfname,scan_sfname); ++incl_depth; if (include) { in_define = 0; strcpy(scan_sfname,ifp); /* Remember rule file's name */ line_nbr = 0; ic = '\n'; } else { in_define = 1; ic = ' '; ibp = ifp; } } 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]; sfp = iep->fp; strcpy(inbuf,iep->buf); ibp = iep->bp; if (in_define) iblisted |= iep->iblisted; else iblisted = iep->iblisted; line_nbr = iep->line_nbr; in_define = iep->in_define; lic = iep->lic; ic = iep->ic; strcpy(scan_sfname,iep->sfname); return 0; } int nextchar() /* Ignores comments and linefeeds */ { lic = ic; for (;;) { if (lic == '\n') { if (in_define) { ic = EOF; if (end_of_file()) return EOF; if (ic == '\n') { /* Define invoked at end of source line */ lic = '\n'; /* Get next input line */ continue; } else { #if CHAR_TRACE printf("nxtchr(1): ic=%d|%c, lic=%d|%c, depth=%d, in_def=%d\n", ic,ic, lic,lic, incl_depth, in_define); #endif return ic; /* This is the char following the define id */ } } else { if (fgets(inbuf, sizeof(inbuf), sfp) == NULL) { ic = EOF; if (end_of_file()) return EOF; if (ic == '\n') { /* Include invoked at end of source line */ lic = '\n'; /* Get next input line */ continue; } else { #if CHAR_TRACE printf( "nxtchr(2): ic=%d|%c, lic=%d|%c, depth=%d, in_def=%d\n", ic,ic, lic,lic, incl_depth, in_define); #endif return ic; /* This is the char following the define id */ } } else { iblisted = 0; ++line_nbr; ibp = inbuf; if (list_source) err_msg(ET_NULL, ""); if (asmint > 1) emit_comment("#> %d: %s", line_nbr,inbuf); } } } ic = *ibp++; if (ic == '#') lic = '\n'; /* Ignore comments */ else if (ic == '\0') { /* Null (but no \n) at end of last line */ ic = '\n'; #if CHAR_TRACE printf("nxtchr(3): ic=%d|%c, lic=%d|%c, depth=%d, in_def=%d\n", ic,ic, lic,lic, incl_depth, in_define); #endif return ic; } else { #if CHAR_TRACE printf("nxtchr(4): ic=%d|%c, lic=%d|%c, depth=%d, in_def=%d\n", ic,ic, lic,lic, incl_depth, in_define); #endif return ic; } } } int nextnb(void) /* Returns 1 if non-blank found */ { while (isspace(ic)) { nextchar(); if (end_of_file()) return 0; } return 1; } void getarg(char *arg) { int count = 0; if (nextnb()) { /* Ignore white space */ do { *arg++ = ic; nextchar(); } while (++count < FNAME_LN && !end_of_file() && ic != ';' && !isspace(ic)); } *arg = '\0'; return; } int getnbr(unsigned long *r, int *base) /* Returns 1 if integer found */ { char *tp = token; /* Copy number's chars into token */ unsigned long v; int hex, c; if (ic == '\'') { /* Character constant */ nextchar(); if (ic == '\\') { ibp = c_esc_char(&v, ibp); /* ibp points to next source char */ ic = *ibp++; *r = v; } else { *r = ic; nextchar(); } if (ic != '\'') { while (isalpha(ic)) nextchar(); if (ic == '\'') { err_msg(ET_ERR, "Char constant must be single character"); nextchar(); } else err_msg(ET_ERR, "Missing ' in char constant"); } else nextchar(); nextnb(); sprintf(token,"%lu", v); return 1; } if (!isxdigit(ic)) return 0; /* Numbers must start with a digit */ *tp++ = tolower(ic); hex = 0; if (ic == '0') { nextchar(); if (!end_of_file()) { if (ic == 'x') { nextchar(); hex = 1; } } } else { if (isalpha(ic)) hex = 1; nextchar(); } if (!end_of_file()) { for (;;) { if (!isxdigit(ic)) break; if (isalpha(ic)) hex = 1; *tp++ = tolower(ic); nextchar(); if (end_of_file()) break; } } *tp = '\0'; nextnb(); if (*base == 0) { /* Base not determined yet */ if (ic == '.' || ic == '!') *base = 10; else if (ic == '-' || hex) *base = 16; else *base = 10; } if ((*base == 10 && ic == '-') || (*base == 16 && (ic == '.' || ic == '!'))) err_msg(ET_ERR, "May not mix hex and decimal (%s)", token); if (hex && *base == 10) err_msg(ET_ERR, "Hex char in decimal number (%s)", token); for (tp = token, v = 0; *tp != '\0'; ) { c = *tp++; if (isdigit(c)) c -= '0'; else c = c-'a' + 10; v = v*(*base) + c; } *r = v; return 1; } #if V6 # if V6DEBUG > 0 void printv6(unsigned char *a) { 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; if (v == 0) ++len; else { if (len > lenx) { stx = st; lenx = len; } st = k; len = 0; } } if (len > lenx) { stx = st; lenx = len; } if (lenx != 0 && stx == 0) { printf(":"); j = lenx; } else { printf("%X", a2[0]); j = 1; } for (; j != IP6_ADDR_LEN/2; ) { if (lenx != 0 && j == stx) { printf(":"); j += lenx; } else { printf(":%X", a2[j]); ++j; } } if (j == stx+lenx) printf(":"); } # endif static int badv6; /* Indicates error for get_v6address() */ int v6err(int whole, int x, char *msg) { char *sv_ibp = ibp; int sv_toklen = toklen; if (whole) { ibp += x; toklen = x; } else { ibp += x+1; toklen = 1; } err_msg(ET_ERR, "Invalid IPv6 address: %s", msg); ibp = sv_ibp; toklen = sv_toklen; badv6 = 1; } unsigned long nbrfromstr(int base, char *cp, int f1, int f2) { int n, c; unsigned long v; for (v = 0, n = f1; n != f2; ++n) { c = tolower(cp[n]); if (isdigit(c)) c -= '0'; else c = c-'a' + 10; v = v*base + c; } if (base == 16 && v > 0xFFFF) v6err(0,n, "hex number > FFFF"); else if (base == 10 && v > 255) v6err(0,n, "decimal number > 255"); return v; } int get_v6address(unsigned char *v6addr, unsigned char *v6ch) { int dots, colons, colon2s; int haveleft, haveright, rightax, dotx; int prevdot, prevcolon, prevcolon2; int x, base, nbrx; char c, d; unsigned long v; unsigned char a[IP6_ADDR_LEN+2]; int ax, j,k; haveleft = haveright = 0; dots = colons = colon2s = 0; prevdot = prevcolon = prevcolon2 = 0; base = 10; dotx = rightax = nbrx = 0; ax = 0; badv6 = 0; if (isxdigit(v6ch[0])) haveleft = 1; for (x = 0; ; ++x) { c = tolower(v6ch[x]); if (!isxdigit(c) && c != '.' && c != ':') { if (colons && nbrx != x && !prevcolon && ax < IP6_ADDR_LEN) { if (dots) { v = nbrfromstr(10, v6ch, nbrx, x); a[ax++] = v; } else { v = nbrfromstr(16, v6ch, nbrx, x); a[ax++] = (v >> 8) & 0xFF; a[ax++] = v & 0xFF; } } break; } if (c == ':') { prevdot = 0; if (dots) v6err(0,x, "colon after dot(s)"); if (prevcolon) { if (prevcolon2) v6err(0,x, "three consecutive colons"); if (!colon2s) { haveright = 1; rightax = ax; } ++colon2s; prevcolon2 = 1; } else { if (nbrx != x && ax < IP6_ADDR_LEN) { v = nbrfromstr(16, v6ch, nbrx, x); a[ax++] = (v >> 8) & 0xFF; a[ax++] = v & 0xFF; } } ++colons; prevcolon = 1; base = 10; } else { if (prevcolon) nbrx = x; prevcolon = prevcolon2 = 0; if (c == '.') { if (prevdot) v6err(0,x, "two consecutive dots"); if (base == 16) v6err(0,x, "hex digit before a dot"); if (nbrx == x) v6err(0,x, "dot follows colon"); else if (colons && base == 10 && !prevdot && ax < IP6_ADDR_LEN) { v = nbrfromstr(10, v6ch, nbrx, x); a[ax++] = v; } if (!dots) dotx = nbrx; ++dots; prevdot = 1; base = 10; } else { if (prevdot) nbrx = x; prevdot = 0; if (!isdigit(c)) base = 16; } } } if (colons) { /* It's a v6 address */ #if V6DEBUG > 1 c = v6ch[x]; v6ch[x] = '\0'; printf("V6V6V6: input v6ch = %s\n", v6ch); v6ch[x] = c; printf(" dots=%d, dotx=%d\n", dots, dotx); printf(" colons=%d, colon2s=%d\n", colons, colon2s); printf(" haveleft=%d, haveright=%d, rightax=%d, ax=%d\n", haveleft, haveright, rightax, ax); #endif memset(v6addr, 0, IP6_ADDR_LEN); if (!badv6) { if (colon2s == 0) { if (dots == 0) { if (colons != 7) v6err(1,x, "should have 7 colons"); } else { if (colons != 6 || dots != 3) v6err(1,x, "should have 6 colons and 3 dots"); } } else if (colon2s == 1) { if (dots == 0) { if (colons > 7) v6err(1,x, "more than 7 colons"); } else { if (colons > 6) v6err(1,x, "more than 6 colons"); if (dots != 3) v6err(1,x, "should have 3 dots"); } } else v6err(1,x, "more than one ::"); if (!badv6) { #if V6DEBUG > 1 printf(" --> rightax=%d, ax=%d, ", rightax, ax); printf("%02x%02x", a[0],a[1]); for (j = 2; j != IP6_ADDR_LEN; j += 2) printf(":%02x%02x", a[j],a[j+1]); printf("\n"); #endif if (!haveright) rightax = ax; if (haveleft) memcpy(v6addr, a, rightax); if (haveright) { k = ax-rightax; memcpy(&v6addr[IP6_ADDR_LEN-k], &a[rightax], k); } #if V6DEBUG > 1 printf(" ==> ax=%d, ", ax); printf("%02x%02x", v6addr[0],v6addr[1]); for (j = 2; j != IP6_ADDR_LEN; j += 2) printf(":%02x%02x", v6addr[j],v6addr[j+1]); printf("\n"); #endif } } ibp = &v6ch[x]; ic = '0'; nextchar(); return 1; //badv6; } else return 0; } #endif /* V6 */ int getaddress(unsigned char *a, int len) /* Return value: 0 = bad, 1 = OK, 2 = v6 OK */ { unsigned long v; int j, base, width; #if V6 if (get_v6address(a, ibp-1)) { # if V6DEBUG > 0 printf(" v6 address = "); printv6(a); printf("\n"); # endif return 2; } #endif base = 0; if (!getnbr(&v, &base)) { /* Get first chunk */ err_msg(ET_ERR, "Number expected"); return 0; } if (ic != '.' && ic != '-' && ic != '!') { /* No width indicator */ for (j = len-1; j >= 0; --j) { /* Fill whole address */ a[j] = v & 0xFF; v = (v>>8) & 0xFF; } return 1; } for (j = 0; ; ) { if (ic == '.' || ic == '-') width = 1; else if (ic == '!') width = 2; if (width == 1) { if (v > 0xFF) err_msg(ET_WARN, "Address byte > 255"); if (j <= len-1) a[j++] = v; } else { if (v > 0xFFFF) err_msg(ET_WARN, "Address field > 65535"); if (j <= len-1) a[j++] = (v>>8) & 0xFF; if (j <= len-1) a[j++] = v & 0xFF; } if (ic != '.' && ic != '-' && ic != '!') break; /* No width indicator for last field */ nextchar(); nextnb(); if (!getnbr(&v, &base)) err_msg(ET_ERR, "Number expected"); } if (j > len) err_msg(ET_WARN, "Too many bytes in address"); return 1; } int get_value(unsigned char *vp, int attrib) { int r; memset(vp,0,RULE_ADDR_LEN); if (toktype == TOK_AFTYPE) { if (attrib != FTLOWPEERTYPE && attrib != FTHIPEERTYPE) err_msg(ET_WARN, "Address family only valid for PeerType attributes"); vp[0] = toksubtype; nextnb(); return 1; } if (toktype == TOK_WKP) { if (attrib != FTLOWTRANSADDRESS && attrib != FTHITRANSADDRESS) err_msg(ET_WARN, "Well-known port only valid for TransAddress attributes"); vp[0] = (toksubtype << 8) & 0xFF; vp[1] = toksubtype & 0xFF; nextnb(); return 1; } if (toktype == TOK_TRANSPR) { if (attrib != FTLOWTRANSTYPE && attrib != FTHITRANSTYPE) err_msg(ET_WARN, "Transport type only valid for TransType attributes"); vp[0] = toksubtype; nextnb(); return 1; } if (toktype != TOK_NUMBER) { ibp -= toklen; ic = ibp[-1]; /* Back up one token */ } switch(attrib) { case FTLOWINTERFACE: case FTLOWADJACENTTYPE: case FTLOWPEERTYPE: case FTLOWTRANSTYPE: case FTHIINTERFACE: case FTHIADJACENTTYPE: case FTHIPEERTYPE: case FTHITRANSTYPE: case FTSOURCECLASS: case FTDESTCLASS: case FTFLOWCLASS: case FTSOURCEKIND: case FTDESTKIND: case FTFLOWKIND: case FTDSCODEPOINT: return getaddress(vp, 1); break; case FTLOWADJACENTADDRESS: case FTHIADJACENTADDRESS: return getaddress(vp, MAC_ADDR_LEN); break; case FTLOWPEERADDRESS: case FTHIPEERADDRESS: r = getaddress(vp, PEER_ADDR_LEN); if (vp[0] == 0 && r == 1) err_msg(ET_WARN, "Peer address has leading zero"); return r; break; case FTLOWTRANSADDRESS: case FTHITRANSADDRESS: return getaddress(vp, TRANS_ADDR_LEN); break; case FTFORWARD: return getaddress(vp, 1); break; case FTV1: case FTV2: case FTV3: case FTV4: case FTV5: return getaddress(vp, RULE_ADDR_LEN); break; #if defined(NETFLOW) case FTMETERID: case FTLOWROUTEPREFIX: case FTHIROUTEPREFIX: return getaddress(vp, 1); break; case FTLOWROUTEASN: case FTHIROUTEASN: return getaddress(vp, TRANS_ADDR_LEN); break; #endif #if defined(NEW_ATR) case FTTOPACKETSIZE: case FTFROMPACKETSIZE: case FTTOINTERARRIVALTIME: case FTFROMINTERARRIVALTIME: # if 0 case FTTOTURNAROUNDTIME: case FTFROMTURNAROUNDTIME: # endif case FTTOBITRATE: case FTFROMBITRATE: case FTTOPDURATE: case FTFROMPDURATE: case FTTOTCPTIME: case FTFROMTCPTIME: case FTTOTCPSIZE: case FTFROMTCPSIZE: 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: return getaddress(vp, DIST_PARAM_LEN); break; } #endif } void get_default_mask(unsigned char *vp, int attrib) { memset(vp,0,RULE_ADDR_LEN); switch(attrib) { case FTLOWINTERFACE: case FTLOWADJACENTTYPE: case FTLOWPEERTYPE: case FTLOWTRANSTYPE: case FTHIINTERFACE: case FTHIADJACENTTYPE: case FTHIPEERTYPE: case FTHITRANSTYPE: case FTSOURCECLASS: case FTDESTCLASS: case FTFLOWCLASS: case FTSOURCEKIND: case FTDESTKIND: case FTFLOWKIND: case FTDSCODEPOINT: vp[0] = 255; return; case FTLOWADJACENTADDRESS: case FTHIADJACENTADDRESS: memset(vp,255,MAC_ADDR_LEN); return; case FTLOWPEERADDRESS: case FTHIPEERADDRESS: memset(vp,255,PEER_ADDR_LEN); return; case FTLOWTRANSADDRESS: case FTHITRANSADDRESS: memset(vp,255,TRANS_ADDR_LEN); return; case FTFORWARD: vp[0] = 255; return; case FTV1: case FTV2: case FTV3: case FTV4: case FTV5: memset(vp,255,RULE_ADDR_LEN); return; #if defined(NETFLOW) case FTMETERID: case FTLOWROUTEPREFIX: case FTHIROUTEPREFIX: vp[0] = 255; return; case FTLOWROUTEASN: case FTHIROUTEASN: memset(vp,255,TRANS_ADDR_LEN); return; #endif } } unsigned long get_number(void) { unsigned long n; int base = 0; getnbr(&n, &base); return n; } int next_token(void) { char *tp = token; int len, r, first_line; struct ident *ip; nextnb(); if (ic == EOF) toktype = TOK_EOF; else if (isalpha(ic)) { for (len = 0; ; ) { if (ic == EOF) break; if (len < sizeof(token)) *tp++ = tolower(ic); ++len; nextchar(); if (!isalnum(ic) && ic != '_') break; } *tp = '\0'; toklen = len; r = lookup(token); ip = &id_table[id_index]; if (r && ip->type != TOK_UNUSED) { /* Found in id_table */ toktype = ip->type; toksubtype = ip->subtype; } else { ip->type = toktype = TOK_SYMBOL; /* New symbol */ if (len > IDENT_LN) { err_msg(ET_WARN, "Identifier with more than %d chars",IDENT_LN); } add_symbol(ST_SYMBOL); } st_ix = ip->stx; /* 0 for` everything below outer block marker */ } else if (isdigit(ic) || ic == '\'') { /* Parser must call get_number() */ strcpy(token, "~"); toklen = 1; toktype = TOK_NUMBER; toksubtype = 0; } else if (ic == '\"') { /* C-style string */ first_line = line_nbr; *tp++ = ic; nextchar(); /* Opening quote */ for (len = 1; ; ) { if (ic == EOF) { err_msg(ET_ERR, "EOF in string which began on line %d", line_nbr); break; } if (len < sizeof(token)) *tp++ = ic; ++len; if (ic == '\"' && tp[-2] != '\\') break; /* Allow " in string */ if (*ibp == '#') { /* Allow # in string */ lic = ic; ic = *ibp++; } else nextchar(); } *tp = '\0'; toklen = len; nextchar(); /* Move past closing quote */ toktype = TOK_STRING; } else { /* Should be a special */ *tp++ = ic; *tp = '\0'; toklen = 1; toktype = TOK_SPECIAL; toksubtype = ic; nextchar(); if (end_of_file()) return TOK_SPECIAL; r = 0; if (lic == '=' && ic == '=') r = SC_EQUAL; else if (lic == '&' && ic == '&') r = SC_LAND; else if (lic == '|' && ic == '|') r = SC_LOR; else if (lic == ':' && ic == '=') r = SC_ASSIGN; if (r) { *tp++ = ic; *tp = '\0'; toklen = 2; toksubtype = r; nextchar(); } } if (testing > 2) printf( "next_token(): token=%s(%d), %s, type=%d, subtype=%u\n", token,toklen, tok_types[toktype], toktype,toksubtype); return toktype; } void get_define(void) { struct ident *ip; int err_type, def_stx, len, ldc; char def_text[10000], *dtp; next_token(); if (toktype != TOK_SYMBOL) { err_type = ET_WARN; if (toktype == TOK_WKP) dtp = "well-known port"; else if (toktype == TOK_TRANSPR) dtp = "transport protocol"; else if (toktype == TOK_AFTYPE) dtp = "address family"; else if (toktype == TOK_RSVWD) { dtp = "SRL reserved word"; err_type = ET_ERR; } else { err_msg(ET_ERR, "Missing DEFINE name"); /* Need to search for ; now */ return; } err_msg(err_type, "'%s' redefines %s %d", token,dtp,toksubtype); if (err_type == ET_ERR) return; else { /* Redfine the symbol */ add_symbol(ST_SYMBOL); ip = &id_table[id_index]; st_ix = ip->stx; ip->type = TOK_SYMBOL; /* Next_token getss this as tokentype */ } } st[def_stx = st_ix].symtype = ST_DEFINE; st[def_stx].d.def_str = ""; next_token(); if (toktype != TOK_SPECIAL || toksubtype != '=') { err_msg(ET_ERR, "= expected"); } else nextnb(); for (dtp = def_text, len = 0, ldc = 'N'; ;) { if (ic == EOF) { err_msg(ET_ERR, "Unterminated DEFINE (';' expected)"); toktype = TOK_EOF; break; } if (ic == ';' && dtp[-1] == '\\') { /* \; in define */ dtp[-1] = ic; } else if (ic == '\n') /* Ignore linefeeds within defines */ ; else if (isspace(ic) && isspace(ldc)) ; /* Compress white space within define text */ else if (ic != ';') { if (len+2 != sizeof(def_text)) /* \n and trailing null */ *dtp++ = ic; ++len; ldc = ic; } else { /* ; ending the define */ if (len+2 > sizeof(def_text)) { err_msg(ET_ERR, "DEFINE too long (more than %d chars)", sizeof(def_text)); len = sizeof(def_text-2); } strcpy(dtp,"\n"); len += 2; dtp = (char *)malloc(len); memcpy(dtp, def_text, len); st[def_stx].d.def_str = dtp; break; } nextchar(); } } void get_cmd_define(char *cmd) { char def_str[250]; int dsl; dsl = strlen(cmd); if (dsl+2 > sizeof(def_str)) dsl = sizeof(def_str)-2; strncpy(def_str, cmd, dsl); strcpy(&def_str[dsl], ";"); push_include(0, def_str); /* Treat def_str like a define */ get_define(); /* Stops at the ; */ ic = EOF; end_of_file(); /* Pop the def_str define */ } int next(void) { int r, stx; char inc_fn[FNAME_LN]; for (;;) { r = next_token(); if (toktype == TOK_RSVWD && toksubtype == RW_DEFINE) { get_define(); continue; } if (toktype == TOK_RSVWD && toksubtype == RW_INCLUDE) { getarg(inc_fn); nextnb(); if (ic != ';') err_msg(ET_ERR, "; expected"); nextchar(); push_include(1,inc_fn); continue; } if (toktype == TOK_SYMBOL) { stx = id_table[id_index].stx; if (st[stx].symtype == ST_DEFINE) { push_include(0, st[stx].d.def_str); continue; } } break; } if (testing) printf("next(): token=%s(%d), %s, type=%d, subtype=%u\n", token,toklen, tok_types[toktype], toktype,toksubtype); return r; }