Class: CiscoAclIntp::Scanner

Inherits:
Object
  • Object
show all
Includes:
SpecialTokenHandler
Defined in:
lib/cisco_acl_intp/scanner.rb

Overview

Lexical analyzer (Scanner)

Constant Summary

Constants included from SpecialTokenHandler

CiscoAclIntp::SpecialTokenHandler::STRING_ARG_TOKENS, CiscoAclIntp::SpecialTokenHandler::STR_REGEXP, CiscoAclIntp::SpecialTokenHandler::SYMBOL_TO_REGEXPSTR

Instance Method Summary collapse

Methods included from SpecialTokenHandler

#convert_tokens_to_regexpstr, #gen_arg_token_lists

Constructor Details

#initializeScanner

Constructor



13
14
15
# File 'lib/cisco_acl_intp/scanner.rb', line 13

def initialize
  @arg_tokens = gen_arg_token_lists
end

Instance Method Details

#check_numd_acl_type(aclnum) ⇒ Array (private)

Numbered ACL header checker

Parameters:

  • aclnum (Integer)

    ACL number

Returns:

  • (Array)

    Token list



74
75
76
77
78
79
80
81
82
# File 'lib/cisco_acl_intp/scanner.rb', line 74

def check_numd_acl_type(aclnum)
  if (1..99).cover?(aclnum) || (1300..1999).cover?(aclnum)
    [:NUMD_STD_ACL, aclnum]
  elsif (100..199).cover?(aclnum) || (2000..2699).cover?(aclnum)
    [:NUMD_EXT_ACL, aclnum]
  else
    [:UNKNOWN, "access-list #{aclnum}"]
  end
end

#run_scaner(acl_text) {|each| ... } ⇒ Array (private)

Exec scanning

Parameters:

  • acl_text (File, String)

    ACL data text

Yields:

  • Pre-process of scanning a line

Yield Parameters:

  • each (String)

    Each line of acl_text (called by ‘each_line` methods)

Returns:

  • (Array)

    Scanned tokens array (Queue)



45
46
47
48
49
50
51
52
# File 'lib/cisco_acl_intp/scanner.rb', line 45

def run_scaner(acl_text)
  queue = []
  acl_text.each_line do |each|
    yield(each)
    queue.concat(scan_one_line(each))
  end
  queue.push [false, 'EOF']
end

#scan_file(file) ⇒ Array

Scan ACL from file to parse

Parameters:

  • file (File)

    File IO object

Returns:

  • (Array)

    Scanned tokens array (Queue)



20
21
22
23
24
# File 'lib/cisco_acl_intp/scanner.rb', line 20

def scan_file(file)
  run_scaner(file) do
    # no-op
  end
end

#scan_line(str) ⇒ Array

Scan ACL from variable

Parameters:

  • str (String)

    Access list string

Returns:

  • (Array)

    Scanned tokens array (Queue)



29
30
31
32
33
34
35
# File 'lib/cisco_acl_intp/scanner.rb', line 29

def scan_line(str)
  run_scaner(str) do |each|
    each.chomp!
    # add word separator at end of line
    each.concat(' ')
  end
end

#scan_match_acl_headerBoolean (private)

Scanner of acl header

Returns:

  • (Boolean)

    if line matched acl header



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/cisco_acl_intp/scanner.rb', line 86

def scan_match_acl_header
  case
  when @ss.scan(/\s*!.*$/), @ss.scan(/\s*#.*$/)
    ## "!/# comment" and whitespace line, NO-OP
  when @ss.scan(/\s+/), @ss.scan(/\A\s*\Z/)
    ## whitespace, NO-OP
    # @line_queue.push [:WHITESPACE, ""] # for debug
  when @ss.scan(/(?:access-list)\s+(\d+)\s/)
    ## Numbered ACL Header
    ## numbered acl has no difference
    ## in format between Standard and Extended...
    @line_queue.push check_numd_acl_type(@ss[1].to_i)
  when @ss.scan(/(ip\s+access\-list)\s/)
    ## Named ACL Header
    @line_queue.push [:NAMED_ACL, @ss[1]]
  end
  @ss.matched?
end

#scan_match_arg_tokensBoolean (private)

Scanner of special tokens

Returns:

  • (Boolean)

    if line matched tokens



145
146
147
148
149
150
151
152
153
154
# File 'lib/cisco_acl_intp/scanner.rb', line 145

def scan_match_arg_tokens
  @arg_tokens.each do |(str, length)|
    next unless @ss.scan(/#{str}/)
    (1...length).each do |idx|
      @line_queue.push token_list(@ss[idx])
    end
    @line_queue.push [:STRING, @ss[length]] # last element
  end
  @ss.matched?
end

#scan_match_commonBoolean (private)

Scanner of common tokens

Returns:

  • (Boolean)

    if line matched tokens



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/cisco_acl_intp/scanner.rb', line 123

def scan_match_common
  case
  when @ss.scan(/(\d+)\s/)
    ## Number
    @line_queue.push [:NUMBER, @ss[1].to_i]
  when @ss.scan(/([\+\-]?#{STR_REGEXP})/)
    ## Tokens (echo back)
    ## defined in module SpecialTokenHandler
    ## plus/minus used in tcp flag token e.g. +syn -ack
    @line_queue.push token_list(@ss[1])
  else
    ## do not match any?
    ## then scanned whole line and
    ## put in @line_queue as unknown.
    @ss.scan(/(.*)$/) # match all
    @line_queue.push [:UNKNOWN, @ss[1]]
  end
  @ss.matched?
end

#scan_match_ipaddrBoolean (private)

Scanner of IP address

Returns:

  • (Boolean)

    if line matched IP address



107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/cisco_acl_intp/scanner.rb', line 107

def scan_match_ipaddr
  case
  when @ss.scan(/(\d+\.\d+\.\d+\.\d+)\s/)
    ## IP Address
    @line_queue.push [:IPV4_ADDR, @ss[1]]
  when @ss.scan(%r{(\d+\.\d+\.\d+\.\d+)(\/)(\d+)\s})
    ## IP Address of 'ip/mask' notation
    @line_queue.push [:IPV4_ADDR, @ss[1]]
    @line_queue.push ['/',        @ss[2]]
    @line_queue.push [:NUMBER,    @ss[3].to_i]
  end
  @ss.matched?
end

#scan_one_line(line) ⇒ Array (private)

Scan a line

Parameters:

  • line (String)

    ACL String

Returns:

  • (Array)

    Scanned tokens array (Queue)



57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/cisco_acl_intp/scanner.rb', line 57

def scan_one_line(line)
  @ss = StringScanner.new(line)
  @line_queue = []
  until @ss.eos?
    case
    when scan_match_arg_tokens
    when scan_match_acl_header
    when scan_match_ipaddr
    else scan_match_common
    end
  end
  @line_queue.push [:EOS, nil] # Add end-of-string
end

#token_list(token) ⇒ Array (private)

Generate echo-backed token array

Parameters:

  • token (String)

    Token

Returns:

  • (Array)

    Token array for scanner queue



159
160
161
# File 'lib/cisco_acl_intp/scanner.rb', line 159

def token_list(token)
  [token, token]
end