filter

package module
v0.0.0-...-a022340 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 15, 2014 License: MIT Imports: 12 Imported by: 0

README

HTTP Package Filter V1.0

#1. 用途 对HTTP GET/POST格式的数据包进行过滤
如果HTTP数据包含下以格式:
GET支持query格式:key1=name1&key2=name2&key3=name3...
POST支持JSON格式:{"key1":name1,"key2":name2,"key3":name3,...}
则可通过过滤器对数据进行过滤操作(允许/拒绝)

#2. 特性

  • 简单高效
  • 多种逻辑运算符
  • 条件分支
  • 正则匹配
  • 内置函数

#3. 例子 一段使用filter的go示例代码:

package main

import (
	"fmt"
	filter "github.com/soforth/gohap"
	"strings"
)

func main() {
	// our filter rule script
	// @ means 'is in list ?' we deny it if result is 1
	//
	filter_rule_script := "gz @ ( '10', 'abc', '303' ) => 1; default => 0"

	// we simulate http GET/POST content as below:
	//
	querys := []string{
		"gz=10&id=123456",
		"gz=303&id=123456",
		"gz=100&id=123456",
		"gz=111&id=123456"}
	// or:
	// querys := []string{
	//      `{"gz":"10","id":"123456"}`,
	//      `{"gz":"303","id":"123456"}`,
	//      `{"gz":"100","id":"123456"}`,
	//      `{"gz":"111","id":"123456"}`}

	// create a parser
	//
	h, err := filter.NewParser(strings.NewReader(filter_rule_script))
	if err != nil {
		panic(err)
	}

	for _, query := range querys {
		// create symbol list
		//
		symlist, err := filter.QueryToSymlist(query)
		// or
		// symlist, err := filter.JsonToSymlist(query)
		//
		if err != nil {
			panic(err)
		}

		// get result value
		//
		result, err := h.Parse(symlist)
		if err != nil {
			panic(err)
		}

		if result == 1 {
			// deny this package(querys[0] and querys[1] are denied because of rule script)
			//
			fmt.Println(query, "is denied")
		}
	}

	// after that, querys[2] and querys[3] passed our test
	// and can be delivered forward
	//
}

// output:
// gz=10&id=123456 is denied
// gz=303&id=123456 is denied
//

该例子包含四步操作:

  • 自定义过滤规则(filter_rule_script),调用API得到解析器句柄(h)
  • HTTP数据包(querys)通过调用API得到符号输入表(symlist)
  • 根据符号输入表,调用解析器句柄的解析API(h.Parse(symlist)),得到结果(result)
  • 根据结果是否符合预期,对数据包做丢弃或进一步处理

#4. 语法手册 ##4.1 类型 字符串、数值是仅有的两种基本类型
字符串由单引号引用,如'abc','hello,world'
数值类型由float64表示,整形亦被转化为float64类型,如123,3.14159265
bool类型最终会转化为数值0.0或1.0

##4.2 变量 变量命名由以下正则表达式描述:
[_a-zA-Z][_a-zA-Z0-9]*
变量在HTTP GET/POST数据包中被定义和赋值,如"gz=10&id=123456"定义了两个变量gz、id;或{"gz":"10","id":"123456"}亦能达到同样目的

##4.3 常量 两种类型的常理,字符型常量、数值型常量

##4.4 函数

函数名说明举例
len()求变量值或常量字符串长度len(gz), len(‘abc’)
count()求变量个数count()
atoi()字符串转换为数字atoi(gz), atoi('123')
itoa()数字转换为字符串itoa(100)
md5()求32位md5值md5(gz, ‘somesalt’), md5(gz)
md5支持1个或多个参数,其值为所有字符串参数拼接后的md5串

##4.5 表达式 过滤器支持以下操作,使用括号改变优先级

逻辑操作名说明操作对象举例
&&逻辑与数值x > 10 && y == 'abc'
||逻辑或数值x > 10 || y == 'abc'
@在列表数值/字符串x @ (202,303)
!@不在列表数值/字符串x !@ ('abc','def')
>大于数值/字符串x > len('abc')
<小于数值/字符串x < 'def'
>=大于等于数值/字符串x >= 10
<=小于等于数值/字符串len('abc') <= 10
==等于数值/字符串10 == x
!=不等于数值/字符串count() != 10
#正则匹配字符串x # '20.*'
!#非正则匹配字符串itoa(20) !# '20'
()括号运算数值x > 10 && ( y == 'abcd' || z == 9 )
=>设置返回值数值x > 10 => 1000
比较操作(@,!@,>,<,>=,<=,==,!=),支持字符串比较和数值比较,字符串比较与C标准库函数strcmp()返回结果约定一致
正则匹配操作(#,!#)右部只能为字符串(正则模式串),支持POSIX-ERE正则匹配(regexp.CompilePOSIX())

##4.6 注释 过滤器支持行注释,以 “//” 开头,直到行尾

##4.7 空格 分号、空格、制表符、换行为分隔符,表达式会自动忽略这些符号

##4.8 语句

  • 过滤器支持多条语句组合,使用空格进行分隔
  • 过滤器支仅支持条件分支语句,条件满足便返回

###例1:测试参数个数: count() == 10 =>1; count() == 9 =>2; default =>0;
解释:如果输入的参数为10个,则返回值为1,如果为9个,则返回值为2,否则返回0
符号'=>'用来设置返回值,不指定符号时返回0(条件不成立)或1(条件成立)
词法分析或语法分析发生错误时返回-1

###例2:测试数据包中变量md5值 md5(x,'@163.com') == '4131bfb2bf25f5d9ef86ff9bf53e0055';
数据包中变量x的内容和'salt'组合后,生成的md5值是否等于右边字符串

###例3:组合测试 count() == 3 && md5(key,'@163.com') == '4131bfb2bf25f5d9ef86ff9bf53e0055' && flag # '^[01]$' && len(value) == 10
匹配成功条件:
HTTP数据包中变量个数为3(key,flag,value),其中变量key和常量字符串'@163.com'组合成后,内容md5值为4131bfb2bf25f5d9ef86ff9bf53e0055, 变量flag取值只能为'0'或'1',变量value值长度为10
则成功的HTTP数据包格式可能为:
GET key=justhechuang&value=1234567890&flag=1
POST {"key":"justhechuang", "value":"1234567890", "flag":"1"}

##4.9 符号输入 HTTP GET/POST数据包即为符号输入
过滤器支持两种类型的符号输入:

  • Query格式,用'='和'&'分隔的字符串
  • JSON格式,Object对象组成的数据

Query格式定义的变量类型全为字符串
而JSON格式定义的变量可以为字符串类型和数值类型
例如:key=justhechuang&value=1234567890&flag=1
定义了三个字符串变量:
变量key,其值为'justhechuang'
变量value,其值为'123456789'
变量flag,其值为'1'
{"key":"justhechuang", "value":"1234567890", "flag":1.0}中,
变量key和value与前述Query格式一致,而flag变量则为float64类型

##4.10 案例 sample目录下有测试用例,每行其格式为:
期望值%过滤规则%符号输入(expect_value%filter_rule%symbol_input)
根据过滤规则和符号输入求的值如果等于期望值,则测试成功,否则为失败

#5. 安装 编译: make
测试: make test
清除: make clean
本程序采用nex加go tool yacc生成
编译nex二进制程序,进入nex目录:go build,然后将生成的nex文件拷贝到系统搜索路径,既能正常编译测试filter nex项目路径

Documentation

Overview

***********************************************************************************

 author: soforth
 date: 2014-9-13
 email: soforth@qq.com
 description: a HTTP package filter, supported BNF as bellow:

 grammer -> expr => RET grammer     // if ( expr ) return RET else return grammer
		| default => RET grammer    // if grammer != 0 return grammer default: return RET
		| expr grammer              // if ( expr) return grammer else return 0
		;
 expr -> expr || term               // logic OR operation
		| expr && term              // logic AND operation
		| term
		;
 term -> factor  @ ( list )         // variable/string/double is in list
		| factor !@ ( list )        // variable/string/double is not in list
		| factor > factor           // left great than right
		| factor < factor           // left less than right
		| factor == factor          // left equal right
		| factor != factor          // left not equal right
		| factor >= factor          // left great than or equal right
		| factor <= factor          // left less than or equal right
		| factor # REGEX            // left regex match right pattern
		| factor !# REGEX           // left regex not match right pattern
		| ( expr )                  // term can be a expr in paren
		;
 list -> factor list;               // list is recursive defined
 factor -> DOUBLE_const             // factor can be double immediate constant
		| STRING_const              // also can be string immediate constant
		| VAR_str                   // also can be variable as symbol input by user
		| func                      // also can be a internal function
		;
 func -> VAR_str ( list );          // function has zero or more arguments

************************************************************************************

Index

Constants

View Source
const (
	EGET  = GKind_t(0)
	DGET  = GKind_t(1)
	EEXPR = GKind_t(2)

	AND  = EKind_t(0)
	OR   = EKind_t(1)
	TERM = EKind_t(2)

	IN   = TKind_t(0)
	NI   = TKind_t(1)
	GT   = TKind_t(2)
	LT   = TKind_t(3)
	EQ   = TKind_t(4)
	NE   = TKind_t(5)
	GE   = TKind_t(6)
	LE   = TKind_t(7)
	MA   = TKind_t(8)
	NM   = TKind_t(9)
	EXPR = TKind_t(10)

	DOUBLE   = FKind_t(0)
	STRING   = FKind_t(1)
	VARIABLE = FKind_t(2)
	FUNCTION = FKind_t(3)

	LEN   = FnKind_t(0)
	MD5   = FnKind_t(1)
	COUNT = FnKind_t(2)
	ATOI  = FnKind_t(3)
	ITOA  = FnKind_t(4)
)
View Source
const CMP = 57356
View Source
const COMMA = 57346
View Source
const CONTAIN = 57357
View Source
const DEFAULT = 57352
View Source
const FUNC = 57358
View Source
const GET = 57351
View Source
const LAND = 57349
View Source
const LOR = 57350
View Source
const LPAREN = 57347
View Source
const NUM = 57355
View Source
const RPAREN = 57348
View Source
const STR = 57354
View Source
const VAR = 57353

Variables

This section is empty.

Functions

func CmpDbl

func CmpDbl(kind TKind_t, d1, d2 float64) (int, error)

func CmpStr

func CmpStr(kind TKind_t, s1, s2 string) (int, error)

func DeleteSymlist

func DeleteSymlist(symlist *SymList)

func DumpSymlist

func DumpSymlist(symlist *SymList)

func EvalCmp

func EvalCmp(kind TKind_t, lfactor, rfactor *Factor, symlist *SymList) (int, error)

func EvalExpr

func EvalExpr(expr *Expr, symlist *SymList) (int, error)

func EvalGrammer

func EvalGrammer(grammer *Grammer, symlist *SymList) (int, error)

func EvalList

func EvalList(kind TKind_t, factor *Factor, list *List, symlist *SymList) (int, error)

func EvalRegex

func EvalRegex(kind TKind_t, lfactor *Factor, regex *regexp.Regexp, symlist *SymList) (int, error)

func EvalTerm

func EvalTerm(term *Term, symlist *SymList) (int, error)

Types

type EKind_t

type EKind_t int // for Expr

type Expr

type Expr struct {
	Kind  EKind_t // AND, OR, TERM
	Left  *Expr
	Right *Term
}

func NewExpr

func NewExpr(kind EKind_t, expr *Expr, term *Term) (*Expr, error)

type FKind_t

type FKind_t int // for Factor & SymList

type Factor

type Factor struct {
	Kind  FKind_t // DOUBLE, STRING, VARIABLE, FUNCTION
	Value interface{}
}

func EvalAtoi

func EvalAtoi(list *List, symlist *SymList) (*Factor, error)

func EvalCount

func EvalCount(symlist *SymList) (*Factor, error)

func EvalFunc

func EvalFunc(fn *Func, symlist *SymList) (*Factor, error)

func EvalItoa

func EvalItoa(list *List, symlist *SymList) (*Factor, error)

func EvalLen

func EvalLen(list *List, symlist *SymList) (*Factor, error)

func EvalMD5

func EvalMD5(list *List, symlist *SymList) (*Factor, error)

func NewFactor

func NewFactor(kind FKind_t, dbl float64, str string, vari string, fn *Func) (*Factor, error)

func SymbolLookup

func SymbolLookup(symlist *SymList, name string) (*Factor, error)

type FnKind_t

type FnKind_t int // for Func

type Func

type Func struct {
	Kind FnKind_t // LEN, MD5, COUNT, ATOI, ITOA
	List *List
}

func NewFunc

func NewFunc(kind FnKind_t, list *List) (*Func, error)

type GKind_t

type GKind_t int // for Grammer

type Grammer

type Grammer struct {
	Kind    GKind_t // EGET, DGET, EEXPR
	Expr    *Expr
	Ret     float64
	Grammer *Grammer
}

func NewGrammer

func NewGrammer(kind GKind_t, expr *Expr, ret float64, grammer *Grammer) (*Grammer, error)

type Lexer

type Lexer struct {
	// contains filtered or unexported fields
}

func NewLexer

func NewLexer(in io.Reader) *Lexer

func NewLexerWithInit

func NewLexerWithInit(in io.Reader, initFun func(*Lexer)) *Lexer

NewLexerWithInit creates a new Lexer object, runs the given callback on it, then returns it.

func (Lexer) Error

func (yylex Lexer) Error(e string)

func (*Lexer) Lex

func (yylex *Lexer) Lex(lval *yySymType) int

func (*Lexer) Text

func (yylex *Lexer) Text() string

type List

type List struct {
	Factor *Factor
	Next   *List
}

func NewList

func NewList(factor *Factor, next *List) (*List, error)

type Parser

type Parser struct {
	// contains filtered or unexported fields
}

parser handle

func NewParser

func NewParser(in io.Reader) (h *Parser, err error)

analyze input rule script and generate parser handle

func (*Parser) Parse

func (h *Parser) Parse(symlist *SymList) (ret int, err error)

get parse result symlist is created by calling QueryToSymlist() or JsonToSymlist() API

type SymList

type SymList struct {
	Kind  FKind_t // DOUBLE, STRING
	Name  string
	Value interface{}
	Next  *SymList
}

func AppendSymlist

func AppendSymlist(symlist *SymList, name, value string, kind FKind_t) (*SymList, error)

func AppendSymlistDouble

func AppendSymlistDouble(symlist *SymList, name string, value float64) (*SymList, error)

func AppendSymlistString

func AppendSymlistString(symlist *SymList, name, value string) (*SymList, error)

func JsonToSymlist

func JsonToSymlist(jstr string) (symlist *SymList, err error)

* parse a JSON string to symlist_t struct, string format should be: * {"double_name":10.0, "interger_name": 99, "string_name":"FIFA WC 2014", ...}

func NewSymlist

func NewSymlist(name, value string, kind FKind_t) (*SymList, error)

func NewSymlistDouble

func NewSymlistDouble(name string, value float64) (*SymList, error)

func NewSymlistString

func NewSymlistString(name, value string) (*SymList, error)

func QueryToSymlist

func QueryToSymlist(query string) (symlist *SymList, err error)

* parse a query string to symlist_t struct , string format should be: * nmq=testmq&mac=xxxx&bootid=xxxx...

type TKind_t

type TKind_t int // for Term

type Term

type Term struct {
	Kind  TKind_t // IN, NI, GT, LT, EQ, NE, GE, LE, MA, NM, EXPR
	Left  *Factor
	Right interface{}
}

func NewTerm

func NewTerm(kind TKind_t, lfactor *Factor, list *List, rfactor *Factor, expr *Expr) (*Term, error)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL