Class: Iptables::Decoder
- Inherits:
-
Object
- Object
- Iptables::Decoder
- Defined in:
- lib/iptables.rb
Overview
This is the internal Decoder class used by methods in the main class.
Instance Attribute Summary collapse
-
#opts ⇒ Object
readonly
Returns the value of attribute opts.
-
#r opts(opts) ⇒ Hash
Options hash set on initialization.
Instance Method Summary collapse
-
#debug(text) ⇒ Object
private
Prints debug output to STDOUT if debug switch is true.
-
#decode(text) ⇒ Hash
Decodes iptables-save input into a normalized hash.
-
#initialize(opts = {}) ⇒ Decoder
constructor
Initialize the decoder object.
- #iptables_backwards_negates ⇒ Object
-
#parse_append_line(line) ⇒ Hash
private
Parses an append line return a hash.
-
#parse_iptables_save(text) ⇒ Hash
private
Takes raw iptables-save input, returns a data hash.
-
#rule(switch_hash) ⇒ Hash
private
Takes a switch_hash and returns the rule as a hash.
-
#shellsplit(line) ⇒ Array
private
Break rule line into pices like a shell.
-
#switch_hash(split) ⇒ Hash
private
Takes an argument array, and returns swtiches and values.
Constructor Details
#initialize(opts = {}) ⇒ Decoder
Initialize the decoder object
38 39 40 41 42 43 |
# File 'lib/iptables.rb', line 38 def initialize(opts = {}) @opts = { :debug => false, :iptables_compatibility => nil, }.merge(opts) end |
Instance Attribute Details
#opts ⇒ Object (readonly)
Returns the value of attribute opts.
29 30 31 |
# File 'lib/iptables.rb', line 29 def opts @opts end |
#r opts(opts) ⇒ Hash
Returns Options hash set on initialization.
29 |
# File 'lib/iptables.rb', line 29 attr_reader :opts |
Instance Method Details
#debug(text) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Prints debug output to STDOUT if debug switch is true
307 308 309 |
# File 'lib/iptables.rb', line 307 def debug(text) puts "D, #{text}" if @opts[:debug] end |
#decode(text) ⇒ Hash
Decodes iptables-save input into a normalized hash
50 51 52 53 54 55 56 57 58 |
# File 'lib/iptables.rb', line 50 def decode(text) { :metadata => { :ruby_iptables_version => VERSION, :iptables_compatibility => opts[:iptables_compatibility], }, :result => parse_iptables_save(text), } end |
#iptables_backwards_negates ⇒ Object
295 296 297 298 299 300 301 |
# File 'lib/iptables.rb', line 295 def iptables_backwards_negates if opts[:iptables_compatibility] == '1.3.5' %w{p s d i o ctorigsrc ctorigdst ctreplsrc ctrepldst espspi length sports dports ports mss} else [] end end |
#parse_append_line(line) ⇒ Hash
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Parses an append line return a hash
115 116 117 118 119 120 121 122 123 124 |
# File 'lib/iptables.rb', line 115 def parse_append_line(line) ss = shellsplit(line) sh = switch_hash(ss) rh = rule(sh) { :shell_split => ss, :swtch_hash => sh, :rule => rh, } end |
#parse_iptables_save(text) ⇒ Hash
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Takes raw iptables-save input, returns a data hash
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/iptables.rb', line 67 def parse_iptables_save(text) # Set the table to nil to begin with so we can detect append lines with no # prior table decleration. table = nil # Input line number for debugging later original_line_number = 0 # Hash for storing the final result hash = {} text.each_line do |line| # If we find a table declaration, change table if line =~ /^\*([a-z]+)$/ table = $1 debug("Found table [#{table}] on line [#{original_line_number}]") end # If we find an append line, parse it if line =~ /^-A (\S+)/ raise NoTable, "Found an append line [#{line}] on line [#{input_line}], but no table yet" if table.nil? chain = $1 line_hash = parse_append_line(line) line_hash[:source] = { :original_line => line, :original_line_number => original_line_number, } hash[table] ||= {} hash[table][chain] ||= {} hash[table][chain][:rules] ||= [] hash[table][chain][:rules] << line_hash end original_line_number += 1 end hash end |
#rule(switch_hash) ⇒ Hash
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Takes a switch_hash and returns the rule as a hash
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/iptables.rb', line 131 def rule(switch_hash) h = { :chain => nil, :parameters => {}, :target => nil, :matches => [], :target_options => {}, } # States match = false match_current = {} target = false switch_hash.each do |sh| sw = sh[:switch] if sw == "A" h[:chain] = sh[:values].first next end # Outside of match and target, these letters are the basic parameters if !match and !target and ["p", "s", "d", "i", "o", "f"].include? sw h[:parameters]["#{sh[:negate]? '!' : ''}#{sw}"] = sh[:values] next end # If option is 'm' then we are in a match if sw == 'm' if match and !match_current.empty? # We were already in a match, stow it h[:matches] << match_current match_current = {} end # Clear the current match match_current = {} match_current[:name] = sh[:values].first # Reset states match = true target = false next end # If option is 'j' then its a target, and anything else is a target_option if sw == "j" if match and !match_current.empty? # We were already in a match, stow it h[:matches] << match_current match_current = {} end h[:target] = sh[:values].first # Reset states target = true match = false next end if match match_current[:options] ||= {} match_current[:options]["#{sh[:negate]? '!' : ''}#{sw}"] = sh[:values] next end if target h[:target_options]["#{sh[:negate]? '!' : ''}#{sw}"] = sh[:values] next end end # Stow away any incomplete matches if match and !match_current.empty? h[:matches] << match_current end h end |
#shellsplit(line) ⇒ Array
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Break rule line into pices like a shell.
The code itself is taken from Ruby core, and supplanted here to work with older rubies.
280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
# File 'lib/iptables.rb', line 280 def shellsplit(line) words = [] field = '' line.scan(/\G\s*(?>([^\s\\\'\"]+)|'([^\']*)'|"((?:[^\"\\]|\\.)*)"|(\\.?)|(\S))(\s|\z)?/m) do |word, sq, dq, esc, garbage, sep| raise ArgumentError, "Unmatched double quote: #{line.inspect}" if garbage field << (word || sq || (dq || esc).gsub(/\\(.)/, '\\1')) if sep words << field field = '' end end words end |
#switch_hash(split) ⇒ Hash
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Takes an argument array, and returns swtiches and values. It returns a hash with switches on the LHS, and values on the right. Values appear as arrays.
For switches without values, the RHS will just be the boolean true.
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
# File 'lib/iptables.rb', line 226 def switch_hash(split) result = [] current = nil debug("processing #{split.inspect}") split.each do |p| debug "p: #{p}" debug "pre current: #{current.inspect}" if current if p =~ /^--?(.+)/ if current and !current.empty? if (current[:negate] and current[:switch]) or !current[:negate] result << current current = {} end else current = {} end current[:switch] = $1 elsif p == '!' if current and !current.empty? unless current[:switch] \ and iptables_backwards_negates.include? current[:switch] result << current current = {} end end current[:negate] = true else raise UnparseableSplit, "Found a value without corresponding arg" unless current current[:values] ||= [] current[:values] << p end debug "post current: #{current.inspect}" if current debug "result: #{result.inspect}" end result << current result end |