【问题标题】:Finding data from text file and displaying result in json format从文本文件中查找数据并以 json 格式显示结果
【发布时间】:2021-03-17 03:52:09
【问题描述】:

有一个 txt 文件,我需要在安全、防火墙下获取值,仅捕获规则号、源、目标端口和协议,如果缺少任何键需要针对没有值的键将默认文本打印为“任何” ,同样需要在文件中获取所述键的数据

文本文件数据


security {
    firewall {
        global-state-policy {
            icmp
            tcp
            udp
        }
        name Local {
            default-action drop
            default-log
            description "Local firewall rules."
            rule 9 {
                action accept
                source {
                    address AccountFront
                }
            }
            rule 10 {
                action accept
                source {
                    address SoftLayerBack
                }
            }
            rule 11 {
                action accept
                source {
                    address SoftLayerFront
                }
            }
            rule 20 {
                action accept
                description "Allow ping reply"
                icmp {
                    type 0
                }
               ------
               ------etc

需要这种形式的输出,

RULE_NAME{
     9
        SOURCE - 'any' if value doesn't exists
        DESTINAION
        PORT
        POROTCOL
    10
        SOURCE
        DESTINAION
        PORT
        POROTCOL
    11
        ....
}

我编写了以下代码,但它返回空列表。 请帮忙

    name, rule, address, destination, port, protocol= [''] * 6
    access_list = []

    with open(path + "mci_vyatta_config.txt", 'r') as fh:
        for line in fh:
            line = line.strip()
            if line:
                line_to_array = line.split(' ')
            if line == "firewall;":
                if line.startswith('name '):
                    name = line_to_array[1]
                    print(name)
                    #to_zone = line_to_array[3]
                elif line.startswith('rule '):
                    rule = line_to_array[1]
                elif line.startswith('address '):
                    address = line_to_array[1].replace(";", "")
                elif line.startswith('destination '):
                    destination = line_to_array[1].replace(";", "")
                elif line.startswith('port '):
                    port = line_to_array[1].replace(";", "")
                elif line.startswith('protocol '):
                    port = line_to_array[1].replace(";", "")
                elif line.startswith('then {'):
                    line = next(fh).strip()  # Gets next line in file
                    access_list.append({'NAME': name,
                                            'RULE': rule,
                                            'SOURCE': address,
                                            'DESTINATION': destination,
                                            'PORT': port,
                                            'PROTOCOL': protocol})

                    name, rule, address, destination, port, protocol= [''] * 6
    return access_list

access_list = read_config("/home/Fathima/workspace/training/")
print(access_list)

有些规则只有源即地址,有些只有端口或协议,如果源、目标端口和协议值存在,我们需要打印值,否则需要显示关键字为'any'

rule 53 {
                action accept
                description "Allow inbound to Zabbix agent"
                protocol tcp
                source {
                    port ZBX_TCP
                }
                state enable
            }
            rule 60 {
                action accept
                description "Allow UDP ports from VPN peers"
                destination {
                    port IPSecPorts
                }
                protocol udp
                source {
                    address IPSecPeers
                }
            }

示例 - 对于规则 53,名称应打印为 53 作为规则名称,协议值应打印为 tcp,端口为 ZBX_TCP,由于未提及地址,因此应打印“任何”

【问题讨论】:

  • @Tahera--在您的示例文本文件中,我们如何将源、目标端口和协议信息与规则相关联?例如,规则 9 具有 { action accept source { address AccountFront} 在您的代码中,您也缺少函数定义行。
  • Func def 已添加到我的原始代码中,此处错过发布
  • 已添加最后一节解释相同,请检查,谢谢@DarrylG

标签: python


【解决方案1】:

这是一个开始。

代码

import re

def parser(filenm):
    '''
        Parser file containing network configuration information
    '''
    rule_block = re.compile(r'\s*rule (?P<rule_number>\d+)\s+\{')  # Line starts a rule block
    address_block = re.compile(r'\s*(?P<address>\w+)\s+\{')    # Start of address info block
    end_block = re.compile(r'\s*\}')              # End block
    
    with open(filenm, 'r') as file:
        stack = []
        bracket_count = 0
        
        for line in file:
            line = line.strip()     # Removes leading/trailing whitespace in line which doesn't matter
            
            if line:                # Process only non-blank lines
                if (m:=rule_block.match(line)):    # Detected Start a new rule
                    bracket_count += 1             # Update Open bracket count
                    nested_type = None
                    
                    # New Dictionary with rule information
                    stack.append({"Rule": m.group('rule_number'), 
                                  "SOURCE": "ANY",
                                  "DESTINATION": "ANY",
                                  "PROTOCOL": "ANY"})   # Start new addresses

                    while (line:=next(file, "").strip()):  # Gets next line in file
                        
                        if end_block.match(line):  # Reached ending block indicator
                            bracket_count -= 1     # Update Close bracket count (i.e. close block)

                            if bracket_count == 0:
                                nested_type = None
                                break              # Done with current rule
                            else:
                                continue

                        if (m:=address_block.match(line)): # Address block in rule
                            nested_type = m.group('address')
                            bracket_count += 1
                            continue

                        data = line.split(maxsplit=1)
                        if len(data) != 2:
                            continue  # skip since has incorrect number of words

                        # Ignore data lines unrelated to desired info
                        if not data[0] in ['action', 'description', 'state']:
                            addresses = stack[-1]
                            if nested_type and data[0].upper()=="ADDRESS":
                                addresses[nested_type.upper()] = data[1]
                            elif nested_type and not nested_type in ['source', 'destination', 'protocol']:
                                addresses['PROTOCOL'] = f"{nested_type.upper()} {' '.join(data)}"
                            else:
                                addresses[data[0].upper()] = data[1]
                
                
    return stack      
   
def display(info):
    '''
        Displays the parsing results
    '''
    print('RULE_NAME {')
    for data in info:
        print(f'\t{data["Rule"]}')
        for k, v in data.items():
            if not "Rule" in k:
                print(f'\t\t{k} {v}')
    print('}')
    

用法

results = parser('ip_rules.txt')
display(results)

输入文件 ip_rules.txt

security {
    firewall {
        global-state-policy {
            icmp
            tcp
            udp
        }
        name Local {
            default-action drop
            default-log
            description "Local firewall rules."
            rule 9 {
                action accept
                source {
                    address AccountFront
                }
            }
            rule 10 {
                action accept
                source {
                    address SoftLayerBack
                }
            }
            rule 11 {
                action accept
                source {
                    address SoftLayerFront
                }
            }
            rule 20 {
                action accept
                description "Allow ping reply"
                icmp {
                    type 0
                }
           }
           rule 53 {
                action accept
                description "Allow inbound to Zabbix agent"
                protocol tcp
                source {
                    port ZBX_TCP
                }
                state enable
            }
            rule 60 {
                action accept
                description "Allow UDP ports from VPN peers"
                destination {
                    port IPSecPorts
                }
                protocol udp
                source {
                    address IPSecPeers
                }
            }
        }
    }
}

输出

RULE_NAME {
    9
        SOURCE AccountFront
        DESTINATION ANY
        PROTOCOL ANY
    10
        SOURCE SoftLayerBack
        DESTINATION ANY
        PROTOCOL ANY
    11
        SOURCE SoftLayerFront
        DESTINATION ANY
        PROTOCOL ANY
    20
        SOURCE ANY
        DESTINATION ANY
        PROTOCOL ICMP type 0
    53
        SOURCE ANY
        DESTINATION ANY
        PROTOCOL tcp
        PORT ZBX_TCP
    60
        SOURCE IPSecPeers
        DESTINATION ANY
        PROTOCOL udp
        PORT IPSecPorts
}

Python 3.6 兼容版本

不使用海象运算符

import re

def parser(filenm):
    '''
        Parser file containing network configuration information
    '''
    rule_block = re.compile(r'\s*rule (?P<rule_number>\d+)\s+\{')  # Line starts a rule block
    address_block = re.compile(r'\s*(?P<address>\w+)\s+\{')    # Start of address info block
    end_block = re.compile(r'\s*\}')              # End block
    
    with open(filenm, 'r') as file:
        stack = []
        bracket_count = 0
        
        for line in file:
            line = line.strip()     # Removes leading/trailing whitespace in line which doesn't matter
            
            if line:                # Process only non-blank lines
                m = rule_block.match(line)
                if m:    # Detected Start a new rule
                    bracket_count += 1             # Update Open bracket count
                    nested_type = None
                    
                    # New Dictionary with rule information
                    stack.append({"Rule": m.group('rule_number'), 
                                  "SOURCE": "ANY",
                                  "DESTINATION": "ANY",
                                  "PROTOCOL": "ANY"})   # Start new addresses
                    
                    line = next(file, "").strip()
                    while line:
                        if end_block.match(line):  # Reached ending block indicator
                            bracket_count -= 1     # Update Close bracket count (i.e. close block)

                            if bracket_count == 0:
                                nested_type = None
                                break              # Done with current rule
                            else:
                                line = next(file, "").strip()  # Gets next line in file
                                continue

                        m = address_block.match(line)
                        if m: # Address block in rule
                            nested_type = m.group('address')
                            bracket_count += 1
                            line = next(file, "").strip()  # Gets next line in file
                            continue

                        data = line.split(maxsplit=1)
                        if len(data) != 2:
                            line = next(file, "").strip()  # Gets next line in file since current line has incorrect number of words
                            continue

                        # Ignore data lines unrelated to desired info
                        if not data[0] in ['action', 'description', 'state']:
                            addresses = stack[-1]
                            if nested_type and data[0].upper()=="ADDRESS":
                                addresses[nested_type.upper()] = data[1]
                            elif nested_type and not nested_type in ['source', 'destination', 'protocol']:
                                addresses['PROTOCOL'] = f"{nested_type.upper()} {' '.join(data)}"
                            else:
                                addresses[data[0].upper()] = data[1]
                              
                            break
                            
                        line = next(file, "").strip()  # Gets next line in file
                
                
    return stack          
        
def display(info):
    '''
        Displays the parsing results
    '''
    print('RULE_NAME {')
    for data in info:
        print(f'\t{data["Rule"]}')
        for k, v in data.items():
            if not "Rule" in k:
                print(f'\t\t{k} {v}')
    print('}')
    
results = parser('ip_rules.txt')
display(results)

【讨论】:

  • 嗨 Darry,感谢您的努力,但在运行代码文件“rule_task1.py”时出现以下错误,第 19 行 if(m:=rule_block.match(line)): # Detected Start a new rule ^ SyntaxError: invalid syntax 如果它必须从具有 n 个规则的巨大文本文件中提取数据,它是否也可以工作?
  • @Tahera——首先是语法错误——你使用的是 Python 3.8+(它引入了海象运算符)吗?如果没有,我将不得不稍微更改代码。
  • Python 3.6.8 - 这是我目前使用的版本
  • @Tahera--我将添加一个应该与 3.6 兼容的版本。应该只需要几分钟。
  • 当然,请慢慢来:)
猜你喜欢
  • 2017-12-04
  • 2020-12-10
  • 1970-01-01
  • 1970-01-01
  • 2017-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多