@@ -382,6 +382,30 @@ def munge_resource_map_from_resource(resource_map_original, compare)
382382 :hashlimit_htable_max , :hashlimit_htable_expire , :hashlimit_htable_gcinterval , :bytecode , :ipvs , :cgroup , :rpfilter , :condition , :name
383383 ]
384384
385+ # Not all arguments are globally unique across all iptables extensions. For matchers we should
386+ # only find within a specific context, a start and end marker can be supplied here. Either a
387+ # plain string or a regex will work; these are passed as an argument to String#index(), and limit
388+ # the search scope. If the resource matches on or after the first matching character in
389+ # context_start, and before the first matching character in context_end, the match succeeds.
390+ @resource_parse_context = {
391+ synproxy_mss : {
392+ context_start : '-j SYNPROXY' ,
393+ } ,
394+ mss : {
395+ # Extra starting space because the matcher for :mss includes '-m tcpmss',
396+ # and the search for it prefixes the matcher with a space
397+ context_start : ' -m tcpmss' ,
398+ context_end : %r{ -[mgj] } ,
399+ } ,
400+ string_to : {
401+ context_start : '-m string' ,
402+ context_end : %r{ -[mgj] } ,
403+ } ,
404+ to : {
405+ context_start : '-j NETMAP' ,
406+ } ,
407+ }
408+
385409 def insert
386410 debug 'Inserting rule %s' % resource [ :name ]
387411 iptables insert_args
@@ -591,17 +615,31 @@ def self.rule_to_hash(line, table, counter)
591615 ############
592616 # Populate parser_list with used value, in the correct order
593617 ############
594- map_index = { }
595- resource_map . each_pair do |map_k , map_v |
596- [ map_v ] . flatten . each do |v |
597- ind = values . index ( %r{\s #{ v } \s } )
598- next unless ind
599- map_index [ map_k ] = ind
618+ index_map = resource_map . each_with_object ( { } ) do |( resource_name , matchers ) , index_mapping |
619+ # Get the start and end markers. If none are defined, use start/end of the rule.
620+ context_start = @resource_parse_context . dig ( resource_name , :context_start ) || %r{^}
621+ context_end = @resource_parse_context . dig ( resource_name , :context_end ) || %r{$}
622+
623+ # Get the offset at which to start searching
624+ search_start = values . index ( context_start )
625+ # If a context marker was defined but wasn't in the string, then the resource can't be here, either
626+ next unless search_start
627+
628+ # Get the offset at which to stop searching
629+ # Start the search for the end marker past the end of context_start, so end markers
630+ # like '-m' won't match against their own start marker (e.g., '-m tcpmss')
631+ context_start = values . match ( context_start ) . to_s if context_start . is_a? Regexp
632+ # If an end marker was defined but wasn't in the string, the context may be the last jump or match
633+ # target in the rule; so if no end marker is found, just use something past the end of the string.
634+ search_end = values . index ( context_end , ( search_start + context_start . length ) ) || values . length
635+
636+ [ matchers ] . flatten . each do |v |
637+ index = values . index ( %r{\s #{ v } \s } , search_start )
638+ next unless index && index < search_end
639+ index_mapping [ resource_name ] = index
600640 end
601641 end
602- # Generate parser_list based on the index of the found option
603- parser_list = [ ]
604- map_index . sort_by { |_k , v | v } . each { |mapi | parser_list << mapi . first }
642+ parser_list = index_map . sort_by { |_resource_name , index | index } . to_h . keys
605643
606644 ############
607645 # MAIN PARSE
0 commit comments