123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- package flowclass
- import (
- "bytes"
- "fmt"
- "strconv"
- "idio.link/go/netaddr/v2"
- "idio.link/go/parser"
- )
- /************************** Pfxs **************************/
- type fcPfxs struct{}
- func (t fcPfxs) Shift(sm *parser.SM, e rune) error {
- switch {
- case e == ' ':
- case e == '{':
- sm.Push(fcPfxSet{})
- case isDigit(e):
- return sm.Push(fcPfxSet{}).Shift(sm, e)
- default:
- return parser.NewUnrecognized("prefixes", e)
- }
- return nil
- }
- func (t fcPfxs) Coalesce(nodes []*parser.CSTNode) any {
- return nodes[0].Coalesce()
- }
- func (t fcPfxs) Value() *bytes.Buffer {
- return nil
- }
- /************************* PfxSet *************************/
- type fcPfxSet struct{}
- func (t fcPfxSet) Shift(sm *parser.SM, e rune) error {
- next := fcSet[fcPfx, *netaddr.NetAddr]{
- newToken: func() fcPfx {
- return fcPfx{}
- },
- }
- if len(sm.Top().Nodes) == 0 {
- return sm.Push(next).Shift(sm, e)
- }
- return parser.NewUnrecognized("prefix set", e)
- }
- func (t fcPfxSet) Coalesce(nodes []*parser.CSTNode) any {
- return nodes[0].Coalesce()
- }
- func (t fcPfxSet) Value() *bytes.Buffer {
- return nil
- }
- /*************************** Pfx **************************/
- type fcPfx struct{}
- func (t fcPfx) Shift(sm *parser.SM, e rune) error {
- // TODO: handle IPv6
- buf := new(bytes.Buffer)
- switch {
- case isDigit(e):
- buf.WriteRune(e)
- sm.Push(fcOctet{val: buf})
- case e == '.':
- sm.Push(fcOctet{val: buf})
- case e == '/':
- sm.Push(fcLength{val: buf})
- default:
- return parser.NewUnrecognized("prefix", e)
- }
- return nil
- }
- func (t fcPfx) Coalesce(nodes []*parser.CSTNode) any {
- var len byte
- addr := make([]byte, 0, 16)
- for _, e := range nodes {
- switch e.ASTNode.(type) {
- case fcOctet:
- addr = append(addr, e.Coalesce().(byte))
- case fcLength:
- len = e.Coalesce().(byte)
- }
- }
- return netaddr.NewNetAddr(addr, int(len))
- }
- func (t fcPfx) Value() *bytes.Buffer {
- return nil
- }
- /************************* Length *************************/
- type fcLength struct {
- val *bytes.Buffer
- }
- func (t fcLength) Shift(sm *parser.SM, e rune) error {
- return accNatural(e, "128", t.val, "length")
- }
- func (t fcLength) Coalesce(_ []*parser.CSTNode) any {
- l, _ := strconv.Atoi(string(t.val.Bytes()))
- return byte(l)
- }
- func (t fcLength) Value() *bytes.Buffer {
- return t.val
- }
- /************************* Octet **************************/
- type fcOctet struct {
- val *bytes.Buffer
- }
- func (t fcOctet) Shift(sm *parser.SM, e rune) error {
- return accNatural(e, "255", t.val, "octet")
- }
- func (t fcOctet) Coalesce(_ []*parser.CSTNode) any {
- o, _ := strconv.Atoi(string(t.val.Bytes()))
- return byte(o)
- }
- func (t fcOctet) Value() *bytes.Buffer {
- return t.val
- }
- func accNatural(
- b rune,
- max string,
- buf *bytes.Buffer,
- msg string,
- ) error {
- switch {
- case isDigit(b):
- dropLeadingZeros(buf)
- buf.WriteRune(b)
- val := buf.Bytes()
- if natGreaterThan(val, []byte(max)) {
- return fmt.Errorf("%s: %s cannot be greater than %s", msg, val, max)
- }
- case buf.Len() == 0:
- return fmt.Errorf("%s: unexpected input: '%s'", msg, string(b))
- default:
- return parser.NewUnrecognized(msg, b)
- }
- return nil
- }
- func dropLeadingZeros(buf *bytes.Buffer) {
- if buf == nil {
- return
- }
- if buf.Len() >= 1 && buf.Bytes()[0] == '0' {
- buf.Truncate(1)
- }
- return
- }
- func natGreaterThan(val []byte, max []byte) bool {
- switch {
- case len(val) < len(max):
- return false
- case len(val) > len(max):
- return true
- }
- for i := 0; i < len(val); i++ {
- if max[i] > val[i] {
- return false
- }
- }
- return true
- }
|