%{ //=========================================================================== // @(#) $Name: cflowd-2-1-b1 $ // @(#) $Id: filtexpr.lex,v 1.8 1999/05/26 11:01:09 dwm Exp $ //=========================================================================== // CAIDA Copyright Notice // // By accessing this software, cflowd++, you are duly informed // of and agree to be bound by the conditions described below in this // notice: // // This software product, cflowd++, is developed by Daniel W. McRobb, and // copyrighted(C) 1998 by the University of California, San Diego // (UCSD), with all rights reserved. UCSD administers the CAIDA grant, // NCR-9711092, under which part of this code was developed. // // There is no charge for cflowd++ software. You can redistribute it // and/or modify it under the terms of the GNU General Public License, // v. 2 dated June 1991 which is incorporated by reference herein. // cflowd++ is distributed WITHOUT ANY WARRANTY, IMPLIED OR EXPRESS, OF // MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE or that the use // of it will not infringe on any third party's intellectual property // rights. // // You should have received a copy of the GNU GPL along with cflowd++. // Copies can also be obtained from: // // http://www.gnu.org/copyleft/gpl.html // // or by writing to: // // University of California, San Diego // // SDSC/CAIDA // 9500 Gilman Dr., MS-0505 // La Jolla, CA 92093 - 0505 USA // // Or contact: // // info@caida.org //=========================================================================== // This module is the lexer used to compile a filter expression into // a vector of tokens. We use this vector in flowfiltlex() to feed // tokens to the parser in FlowFilter.y. // The reason it's done this way: avoid having to lex a filter expression // for every flow. Instead, the parser can use the pre-built token // vector by calling flowfiltlex(). This speeds things up considerably. //=========================================================================== extern "C" { #include #include #include } #include #include "CflowdRawFlow.hh" #include "CflowdFlowFilter.hh" #include "flowfilt.tab.h" extern int flowfiltlval; extern int flowfiltparse (void); static const string rcsid = "@(#) $Name: cflowd-2-1-b1 $ $Id: filtexpr.lex,v 1.8 1999/05/26 11:01:09 dwm Exp $"; static const char *g_expression; static int g_compileReturn; extern int flowfiltparseval; CflowdRawFlow::index_type g_fieldMask; uint32_t g_value; static int charnum = 0; static struct tm g_Tm; void filtexprerror(const char *msg); %} %option noyywrap %x INERROR %% /* flow field keywords */ all {charnum += strlen(yytext); flowfiltlval = 1; return ALL; /* matches all flows */} router {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_routerMask; return FIELDNAME;} srcaddr {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_srcIpAddrMask; return FIELDNAME;} dstaddr {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_dstIpAddrMask; return FIELDNAME;} nexthop {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_ipNextHopMask; return FIELDNAME;} srcport {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_srcPortMask; return FIELDNAME;} dstport {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_dstPortMask; return FIELDNAME;} srcas {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_srcAsMask; return FIELDNAME;} dstas {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_dstAsMask; return FIELDNAME;} srcmask {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_srcMaskLenMask; return FIELDNAME;} dstmask {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_dstMaskLenMask; return FIELDNAME;} tcpflags {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_dstMaskLenMask; return FIELDNAME;} protocol {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_protocolMask; return FIELDNAME;} tos {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_tosMask; return FIELDNAME;} inputif {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_inputIfIndexMask; return FIELDNAME;} outputif {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_outputIfIndexMask; return FIELDNAME;} pkts {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_pktsMask; return FIELDNAME;} bytes {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_bytesMask; return FIELDNAME;} starttime {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_startTimeMask; return FIELDNAME;} endtime {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_endTimeMask; return FIELDNAME;} enginetype {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_engineTypeMask; return FIELDNAME;} engineid {charnum += strlen(yytext); g_fieldMask = CflowdRawFlow::k_engineIdMask; return FIELDNAME;} /* other keywords */ now {charnum += strlen(yytext); g_value = time((time_t *)0); return INTEGER;} /* IP addresses */ [0-9]+[.][0-9]+[.][0-9]+[.][0-9]+ {charnum += strlen(yytext); g_value = inet_addr(yytext); return INTEGER;} /* Match a date and time of the form 'MM/DD/YY[YY] hh:mm:ss', convert */ /* to an integer of seconds since UNIX epoch. */ [0-9]+[/][0-9]+[/][0-9]+[ ]+[0-9]+[\:][0-9][0-9][\:][0-9][0-9] { charnum += strlen(yytext); memset(&g_Tm,0,sizeof(g_Tm)); if (sscanf(yytext, "%d/%d/%d %d:%02d:%02d",&g_Tm.tm_mon,&g_Tm.tm_mday, &g_Tm.tm_year,&g_Tm.tm_hour,&g_Tm.tm_min,&g_Tm.tm_sec) != 6) { filtexprerror("bad date format: use MM/DD/YYYY HH:MM:SS"); exit(1); } else { g_Tm.tm_mon --; g_Tm.tm_isdst = -1; if (g_Tm.tm_year >= 1900) { g_Tm.tm_year -= 1900; } else { filtexprerror("warning: you should use YYYY for year."); if (g_Tm.tm_year < 96) { g_Tm.tm_year += 100; } else { if (g_Tm.tm_year > 100) { filtexprerror("bad date format: use MM/DD/YYYY HH:MM:SS"); exit(1); } } fprintf(stderr,"assuming year %d.",g_Tm.tm_year+1900); } g_value = mktime(&g_Tm); return INTEGER; } } /* numbers in base 10 */ [0-9]+ {charnum += strlen(yytext); g_value = atoi(yytext); return INTEGER;} /* numbers in hexadecimal */ 0x[0-9a-fA-F]+ {charnum += strlen(yytext); g_value = strtoul(yytext,(char **)NULL,16); return INTEGER;} [ \t]+ {charnum += strlen(yytext); /* skip whitespace */ } /* operators */ [!][=] {charnum += 2; return(NE); /* not equal */ } [=][=] {charnum += 2; return(EQ); /* equal */ } [<] {charnum++; return(LT); /* less than */ } [>] {charnum++; return(GT); /* greater than */ } [<][=] {charnum += 2; return(LE); /* less than or equal */ } [>][=] {charnum += 2; return(GE); /* greater than or equal */ } [=] {charnum++; return(EQ); /* equal */ } [\&][\&] {charnum += 2; return(AND); /* and */ } [\&] {charnum++; return(BITAND); /* bitwise and */ } [\|][\|] {charnum += 2; return(LOGOR); /* logical or */ } [\|] {charnum++; return(BITOR); /* bitwise or */ } [\(] {charnum++; return(LPAREN); /* left paren */ } [\)] {charnum++; return(RPAREN); /* right paren */ } [/] {charnum++; return(DIV); /* divide */ } [*] {charnum++; return(MUL); /* multiply */ } [+] {charnum++; return(ADD); /* add */ } [-] {charnum++; return(SUB); /* subtract */ } [%] {charnum++; return(MOD); /* modulo */ } [~] {charnum++; return(BITNOT); /* bitwise not */ } [!] {charnum++; return(LOGNOT); /* logical not */ } \n {charnum++; return(0);} <> {return(0);} . {charnum++; BEGIN(INERROR); yyless(0);} [a-zA-Z]+ {return(1);} [^a-zA-Z]* {return(1);} %% //------------------------------------------------------------------------- // void filtexprerror(const char *msg) //......................................................................... // //------------------------------------------------------------------------- void filtexprerror(const char *msg) { char fmtString[10]; fprintf(stderr,"[E] %s at '%s':\n",msg,yytext); fprintf(stderr,"%s\n",g_expression); sprintf(fmtString,"%%%ds\n",charnum); fprintf(stderr,fmtString,"^"); // exit(1); g_compileReturn = -1; return; } //------------------------------------------------------------------------- // void flowfilterror(const char *msg) //......................................................................... // //------------------------------------------------------------------------- void flowfilterror(const char *msg) { filtexprerror(msg); return; } //------------------------------------------------------------------------- // int CompileExpression(const char *expression, // CflowdFlowFilter & flowFilter) //......................................................................... // Compiles expression into flowFilter. Returns 0 on success, -1 // on failure. //------------------------------------------------------------------------- int CompileExpression(const char *expression, CflowdFlowFilter & flowFilter) { int lexRc = 1; CflowdFlowFilterLexedToken newToken; YY_BUFFER_STATE bufferState; g_compileReturn = 0; g_expression = expression; bufferState = yy_scan_string(expression); // loop and lex, pushing tokens into flowFilter. while (lexRc != 0) { lexRc = filtexprlex(); newToken.lexToken = lexRc; newToken.fieldMask = 0; newToken.value = 0; switch (lexRc) { case FIELDNAME: // We got a flow field name. newToken.fieldMask = g_fieldMask; break; case INTEGER: // We got a value of some kind. newToken.value = g_value; break; case INERROR: // We got something we don't understand. flowfilterror("parse error"); g_compileReturn = -1; lexRc = 0; break; default: // Assume we got an operator. break; } // push token onto flowFilter. flowFilter.push_back(newToken); } yy_delete_buffer(bufferState); return(g_compileReturn); }