summaryrefslogtreecommitdiffhomepage
path: root/packet/bgp
diff options
context:
space:
mode:
authorMatthieu Texier <matthieu@texier.tv>2017-03-02 15:56:02 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2017-03-02 15:56:02 +0900
commit55e96842593e9645ea0866398d57cfa8a8530385 (patch)
tree7d821ee75f9a787b6735e6d75c52622aef2b607e /packet/bgp
parent9a28be912628741654140edf8e3d77a2028a96e8 (diff)
flowspec: comply with new draft RFC5575bis normalized operators
Diffstat (limited to 'packet/bgp')
-rw-r--r--packet/bgp/bgp.go173
-rw-r--r--packet/bgp/bgp_test.go6
-rw-r--r--packet/bgp/constant.go55
3 files changed, 184 insertions, 50 deletions
diff --git a/packet/bgp/bgp.go b/packet/bgp/bgp.go
index ece8692e..a911c411 100644
--- a/packet/bgp/bgp.go
+++ b/packet/bgp/bgp.go
@@ -2591,60 +2591,124 @@ func doFlowSpecNumericParser(rf RouteFamily, args []string, validationFunc func(
if afi, _ := RouteFamilyToAfiSafi(rf); afi == AFI_IP && FlowSpecValueMap[args[0]] == FLOW_SPEC_TYPE_LABEL {
return nil, fmt.Errorf("flow label spec is only allowed for ipv6")
}
- exp := regexp.MustCompile("^((<=|>=|[<>=])(\\d+)&)?(<=|>=|[<>=])?(\\d+)$")
+ cmdType := args[0]
+ args = append(args[:0], args[1:]...) // removing command string
+ fullCmd := strings.Join(args, " ") // rebuiling tcp filters
+ opsFlags, err := parseDecValuesCmd(fullCmd, validationFunc)
+ if err != nil {
+ return nil, err
+ }
items := make([]*FlowSpecComponentItem, 0)
-
- f := func(and bool, o, v string) (*FlowSpecComponentItem, error) {
- op := 0
- if and {
- op |= 0x40
- }
- if len(o) == 0 {
- op |= 0x1
- }
- for _, oo := range o {
- switch oo {
- case '>':
- op |= 0x2
- case '<':
- op |= 0x4
- case '=':
- op |= 0x1
- }
- }
- value, err := strconv.Atoi(v)
- if err != nil {
- return nil, err
- }
- err = validationFunc(value)
- if err != nil {
- return nil, err
- }
- return NewFlowSpecComponentItem(op, value), nil
+ for _, opFlag := range opsFlags {
+ items = append(items, NewFlowSpecComponentItem(opFlag[0], opFlag[1]))
}
+ return NewFlowSpecComponent(FlowSpecValueMap[cmdType], items), nil
+}
- for _, arg := range args[1:] {
- var and bool
- elems := exp.FindStringSubmatch(arg)
- if len(elems) == 0 {
- return nil, fmt.Errorf("invalid flowspec numeric item")
- }
- if elems[1] != "" {
- and = true
- item, err := f(false, elems[2], elems[3])
+func parseDecValuesCmd(myCmd string, validationFunc func(int) error) ([][2]int, error) {
+ var index int = 0
+ var decOperatorsAndValues [][2]int
+ var operatorValue [2]int
+ var errorNum error
+ for index < len(myCmd) {
+ myCmdChar := myCmd[index : index+1]
+ switch myCmdChar {
+ case DECNumOpNameMap[DEC_NUM_OP_GT], DECNumOpNameMap[DEC_NUM_OP_LT]:
+ // We found a < or > let's check if we face >= or <=
+ if myCmd[index+1:index+2] == "=" {
+ myCmdChar = myCmd[index : index+2]
+ index++
+ }
+ if bit := DECNumOpValueMap[myCmdChar]; bit&DECNumOp(operatorValue[0]) == 0 {
+ operatorValue[0] |= int(bit)
+ index++
+ } else {
+ err := fmt.Errorf("Operator > < or >= <= appears multiple times")
+ return nil, err
+ }
+ case "!", "=":
+ // we found the beginning of a not let's check secong character
+ if myCmd[index+1:index+2] == "=" {
+ myCmdChar = myCmd[index : index+2]
+ if bit := DECNumOpValueMap[myCmdChar]; bit&DECNumOp(operatorValue[0]) == 0 {
+ operatorValue[0] |= int(bit)
+ index += 2
+ } else {
+ err := fmt.Errorf("Not or Equal operator appears multiple time")
+ return nil, err
+ }
+ } else {
+ err := fmt.Errorf("Malformated not or equal operator")
+ return nil, err
+ }
+ case "t", "f": // we could be facing true or false, let's check
+ if myCmd == DECNumOpNameMap[DEC_NUM_OP_FALSE] || myCmd == DECNumOpNameMap[DEC_NUM_OP_TRUE] {
+ if bit := DECNumOpValueMap[myCmd]; bit&DECNumOp(operatorValue[0]) == 0 {
+ operatorValue[0] |= int(bit)
+ index = index + len(myCmd)
+ } else {
+ err := fmt.Errorf("Boolean operator appears multiple times")
+ return nil, err
+ }
+ } else {
+ err := fmt.Errorf("Boolean operator %s badly formatted", myCmd)
+ return nil, err
+ }
+ case DECLogicOpNameMap[DEC_LOGIC_OP_AND], DECLogicOpNameMap[DEC_LOGIC_OP_OR]:
+ if bit := DECLogicOpValueMap[myCmdChar]; bit&DECLogicOp(operatorValue[0]) == 0 {
+ if myCmdChar == DECLogicOpNameMap[DEC_LOGIC_OP_AND] {
+ operatorValue[0] |= int(bit)
+ }
+ decOperatorsAndValues = append(decOperatorsAndValues, operatorValue)
+ operatorValue[0] = 0
+ operatorValue[1] = 0
+ index++
+ } else {
+ err := fmt.Errorf("AND or OR (space) operator appears multiple time")
+ return nil, err
+ }
+ case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9":
+ myLoopChar := myCmdChar
+ loopIndex := index
+ // we loop till we reach the end of decimal value
+ // exit conditions : we reach the end of decimal value (we found & or ' ') or we reach the end of the line
+ for loopIndex < len(myCmd) &&
+ (myLoopChar != DECLogicOpNameMap[DEC_LOGIC_OP_AND] && myLoopChar != DECLogicOpNameMap[DEC_LOGIC_OP_OR]) {
+ // we check if inspected charater is a number
+ if _, err := strconv.Atoi(myLoopChar); err == nil {
+ // we move to next character
+ loopIndex++
+ if loopIndex < len(myCmd) {
+ myLoopChar = myCmd[loopIndex : loopIndex+1] // we move to the next character only if we didn't reach the end of cmd
+ }
+ } else {
+ err := fmt.Errorf("Decimal value badly formatted: %s", myLoopChar)
+ return nil, err
+ }
+ }
+ decimalValueString := myCmd[index:loopIndex]
+ operatorValue[1], errorNum = strconv.Atoi(decimalValueString)
+ if errorNum != nil {
+ return nil, errorNum
+ }
+ err := validationFunc(operatorValue[1])
if err != nil {
return nil, err
}
- items = append(items, item)
- }
- item, err := f(and, elems[4], elems[5])
- if err != nil {
+ // we check if we found any operator, if not we set default as ==
+ if operatorValue[0] == 0 {
+ operatorValue[0] = DEC_NUM_OP_EQ
+ }
+ // we are done with decimal value, we give back the next cooming charater to the main loop
+ index = loopIndex
+ default:
+ err := fmt.Errorf("%s not part of flowspec decimal value or operators", myCmdChar)
return nil, err
}
- items = append(items, item)
}
-
- return NewFlowSpecComponent(FlowSpecValueMap[args[0]], items), nil
+ operatorValue[0] |= int(DECLogicOpValueMap["E"])
+ decOperatorsAndValues = append(decOperatorsAndValues, operatorValue)
+ return decOperatorsAndValues, nil
}
func flowSpecNumericParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
@@ -3127,12 +3191,27 @@ func formatNumericOp(op int) string {
return opstr
}
+func formatNumericOpFrontQty(op int) string {
+ gtlteqOnly := op & 0x07
+ return fmt.Sprintf("%s", DECNumOpNameMap[DECNumOp(gtlteqOnly)])
+}
+
+func formatNumericOpBackLogic(op int) string {
+ andOrOnly := op & 0x40 // let's ignore the END bit to avoid having an E at the end of the string
+ return fmt.Sprintf("%s", DECLogicOpNameMap[DECLogicOp(andOrOnly)])
+}
+
func formatNumeric(op int, value int) string {
- return fmt.Sprintf("%s%d", formatNumericOp(op), value)
+ gtlteqOnly := op & 0x07
+ if DECNumOp(gtlteqOnly) == DECNumOpValueMap[DECNumOpNameMap[DEC_NUM_OP_FALSE]] || DECNumOp(gtlteqOnly) == DECNumOpValueMap[DECNumOpNameMap[DEC_NUM_OP_TRUE]] {
+ return fmt.Sprintf("%s%s", formatNumericOpFrontQty(op), formatNumericOpBackLogic(op))
+ } else {
+ return fmt.Sprintf("%s%d%s", formatNumericOpFrontQty(op), value, formatNumericOpBackLogic(op))
+ }
}
func formatProto(op int, value int) string {
- return fmt.Sprintf("%s%s", formatNumericOp(op), Protocol(value).String())
+ return fmt.Sprintf("%s%s%s", formatNumericOpFrontQty(op), Protocol(value).String(), formatNumericOpBackLogic(op))
}
func formatFlag(op int, value int) string {
diff --git a/packet/bgp/bgp_test.go b/packet/bgp/bgp_test.go
index cee2b3ab..e0f1a5ca 100644
--- a/packet/bgp/bgp_test.go
+++ b/packet/bgp/bgp_test.go
@@ -519,13 +519,13 @@ func Test_EVPNIPPrefixRoute(t *testing.T) {
func Test_CompareFlowSpecNLRI(t *testing.T) {
assert := assert.New(t)
- cmp, err := ParseFlowSpecComponents(RF_FS_IPv4_UC, "destination 10.0.0.2/32 source 10.0.0.1/32 destination-port =3128 protocol tcp")
+ cmp, err := ParseFlowSpecComponents(RF_FS_IPv4_UC, "destination 10.0.0.2/32 source 10.0.0.1/32 destination-port ==3128 protocol tcp")
assert.Nil(err)
n1 := &FlowSpecNLRI{Value: cmp, rf: RF_FS_IPv4_UC}
- cmp, err = ParseFlowSpecComponents(RF_FS_IPv4_UC, "source 10.0.0.0/24 destination-port =3128 protocol tcp")
+ cmp, err = ParseFlowSpecComponents(RF_FS_IPv4_UC, "source 10.0.0.0/24 destination-port ==3128 protocol tcp")
assert.Nil(err)
n2 := &FlowSpecNLRI{Value: cmp, rf: RF_FS_IPv4_UC}
- cmp, err = ParseFlowSpecComponents(RF_FS_IPv4_UC, "source 10.0.0.9/32 port =80 =8080 destination-port >8080&<8080 =3128 source-port >1024 protocol udp tcp")
+ cmp, err = ParseFlowSpecComponents(RF_FS_IPv4_UC, "source 10.0.0.9/32 port ==80 ==8080 destination-port >8080&<8080 ==3128 source-port >1024 protocol ==udp ==tcp")
n3 := &FlowSpecNLRI{Value: cmp, rf: RF_FS_IPv4_UC}
assert.Nil(err)
cmp, err = ParseFlowSpecComponents(RF_FS_IPv4_UC, "destination 192.168.0.2/32")
diff --git a/packet/bgp/constant.go b/packet/bgp/constant.go
index 4888df7f..faa156e1 100644
--- a/packet/bgp/constant.go
+++ b/packet/bgp/constant.go
@@ -154,6 +154,61 @@ var TCPFlagOpValueMap = map[string]TCPFlagOp{
TCPFlagOpNameMap[TCP_FLAG_OP_MATCH]: TCP_FLAG_OP_MATCH,
}
+type DECNumOp int
+
+const (
+ DEC_NUM_OP_TRUE = 0x00 // true always with END bit set
+ DEC_NUM_OP_EQ = 0x01
+ DEC_NUM_OP_GT = 0x02
+ DEC_NUM_OP_GT_EQ = 0x03
+ DEC_NUM_OP_LT = 0x04
+ DEC_NUM_OP_LT_EQ = 0x05
+ DEC_NUM_OP_NOT_EQ = 0x06
+ DEC_NUM_OP_FALSE = 0x07 // true always with END bit set
+)
+
+var DECNumOpNameMap = map[DECNumOp]string{
+ DEC_NUM_OP_TRUE: "true",
+ DEC_NUM_OP_EQ: "==",
+ DEC_NUM_OP_GT: ">",
+ DEC_NUM_OP_GT_EQ: ">=",
+ DEC_NUM_OP_LT: "<",
+ DEC_NUM_OP_LT_EQ: "<=",
+ DEC_NUM_OP_NOT_EQ: "!=",
+ DEC_NUM_OP_FALSE: "false",
+}
+
+var DECNumOpValueMap = map[string]DECNumOp{
+ DECNumOpNameMap[DEC_NUM_OP_TRUE]: DEC_NUM_OP_TRUE,
+ DECNumOpNameMap[DEC_NUM_OP_EQ]: DEC_NUM_OP_EQ,
+ DECNumOpNameMap[DEC_NUM_OP_GT]: DEC_NUM_OP_GT,
+ DECNumOpNameMap[DEC_NUM_OP_GT_EQ]: DEC_NUM_OP_GT_EQ,
+ DECNumOpNameMap[DEC_NUM_OP_LT]: DEC_NUM_OP_LT,
+ DECNumOpNameMap[DEC_NUM_OP_LT_EQ]: DEC_NUM_OP_LT_EQ,
+ DECNumOpNameMap[DEC_NUM_OP_NOT_EQ]: DEC_NUM_OP_NOT_EQ,
+ DECNumOpNameMap[DEC_NUM_OP_FALSE]: DEC_NUM_OP_FALSE,
+}
+
+type DECLogicOp int
+
+const (
+ DEC_LOGIC_OP_END = 0x80
+ DEC_LOGIC_OP_OR = 0x00
+ DEC_LOGIC_OP_AND = 0x40
+)
+
+var DECLogicOpNameMap = map[DECLogicOp]string{
+ DEC_LOGIC_OP_OR: " ",
+ DEC_LOGIC_OP_AND: "&",
+ DEC_LOGIC_OP_END: "E",
+}
+
+var DECLogicOpValueMap = map[string]DECLogicOp{
+ DECLogicOpNameMap[DEC_LOGIC_OP_OR]: DEC_LOGIC_OP_OR,
+ DECLogicOpNameMap[DEC_LOGIC_OP_AND]: DEC_LOGIC_OP_AND,
+ DECLogicOpNameMap[DEC_LOGIC_OP_END]: DEC_LOGIC_OP_END,
+}
+
func (f TCPFlag) String() string {
ss := make([]string, 0, 6)
for _, v := range []TCPFlag{TCP_FLAG_FIN, TCP_FLAG_SYN, TCP_FLAG_RST, TCP_FLAG_PUSH, TCP_FLAG_ACK, TCP_FLAG_URGENT, TCP_FLAG_CWR, TCP_FLAG_ECE} {