Skip to main content
Loading...

More Python Posts

from itertools import product
V='∀'
E='∃'


def tt(f,n) :
  xss=product((0,1),repeat=n)
  print('function:',f.__name__)
  for xs in xss : print(*xs,':',int(f(*xs)))
  print('')

# p \/ (q /\ r) = (p \/ q) /\ (p \/ r)

def prob1(p,q,r) :
  x=p or (q and r)
  y= (p or q) and (p or r)
  return x==y

tt(prob1,3)

# p/\(q\/r)=(p/\q)\/(p/\r)

def prob2(p,q,r) :
  x=p and ( q or r )
  y=(p and q) or (p and r)
  return x==y

tt(prob2,3)

#~(p/\q)=(~p\/~q)

def prob3(p,q) :
  x=not (p and q)
  y=(not p) or (not q)
  return x==y
tt(prob3,2)

#(~(p\/q))=((~p)/\~q)

def prob4(p, q):
   x = not(p or q)
   y = not p and not q
   return x == y

tt(prob4, 2)

#(p/\(p=>q)=>q)

def prob5(p,q):
  x= p and ( not p or q)
  return not x or q
    
tt(prob5,2)

# (p=>q)=((p\/q)=q)

def prob6(p,q) :
  x = (not p or q)
  y=((p or q) == q)
  return x==y
 
tt(prob6,2)


#((p=>q)=(p\/q))=q
def prob7(p,q):
  if ((not p or q)==(p or q))==q:
    return 1
 
tt(prob7,2)



#(p=>q)=((p/\q)=p)
def prob8(p,q):
  if (not p or q)==((p and q)==p):
    return 1
 
tt(prob8,2)


#((p=>q)=(p/\q))=p

def prob9(p,q):
  if ((not p or q)==(p and q))==p:
    return '1'

tt(prob9,2)



#(p=>q)/\(q=>r)=>(p=>r)
def prob10(p,q,r) :
  x = not ((not p or q) and (not q or r)) or (not p or r)
  return x
 
tt(prob10, 3)


# (p = q) /\ (q => r)  => (p => r)
#answer 1
def prob11(p,q,r) :
  x = not((p is q) and (not q or r)) or (not p or r)
  return x
 
tt(prob11, 3)

#(p=q)/\(q=>r)=>(p=>r)
#answer 2
def prob11(p,q,r):
  x=(p==q) and (not q or r)
  y=not p or r
  return not x or y

tt(prob11,3)

#((p=>q)/\(q=r))=>(p=>r)

def prob12(p,q,r):
  x=(not p or q) and ( q==r )
  y=not p or r
  return not x or y

tt(prob12,3)

#(p=>q)=>((p/\r)=>(q/\r))

def prob13(p,q,r):
  x=not p or q
  y=(not(p and r) or ( q and r))
  return not x or y

tt(prob13,3)

#Question#2----------------------------------------

#(p=>q)=>r=p=>(q=>r)

def prob14(p,q,r):
  x=(not(not p or q) or r)
  y=(not p or (not q or r))
  return x==y

tt(prob14,3) 


def prob15(p, q):
    x = not(p and q)
    y = not p and not q
    return x == y

tt(prob15, 2)


def prob16(p, q):
    x = not(p or q)
    y = not p or not q
    return x == y

tt(prob16, 2)



def prob17(p):
    x = p
    y = not p
    return x == y

tt(prob17, 1)
import subprocess
import logging
import re
from typing import Dict, Any, List, Optional


class BGPRouter:
    """BGP Router class for parsing and managing BGP route information."""
    
    def __init__(self, local_asn: str = '65412'):
        """Initialize BGP router with local ASN.
        
        Args:
            local_asn: Local BGP ASN number
        """
        self.local_asn = local_asn
        
    def _normalize_network_cidr(self, network: str) -> str:
        """Normalize network address by adding appropriate CIDR notation.
        
        Args:
            network: Network address (e.g., "172.31.0.0" or "172.16.0.1/32")
            
        Returns:
            Network address with appropriate CIDR notation
        """
        if '/' in network:
            return network
            
        try:
            octets = network.split('.')
            if len(octets) != 4:
                return network  # Invalid IP format or IPv6, return as-is

            # Determine CIDR based on trailing zero pattern

            # Check for default route
            if network == '0.0.0.0':
                return '0.0.0.0/0'

            if octets[1:] == ['0', '0', '0']:
                return f"{network}/8"

            if octets[2:] == ['0', '0']:
                return f"{network}/16"

            if octets[3] == '0':
                return f"{network}/24"
 
        except (ValueError, IndexError):
            return network
        

    def _parse_as_path(self, path_info: str) -> str:
        """Extract AS path from BGP path information.
        
        Args:
            path_info: Raw path information from BGP output
            
        Returns:
            Cleaned AS path string
        """
        path_info = path_info.strip()
        
        # Handle internal routes
        if path_info == 'i':
            return self.local_asn
            
        # Extract AS numbers using list comprehension
        path_parts = path_info.split()
        as_numbers = [part for part in path_parts if part.isdigit()]
        
        return ' '.join(as_numbers)

    def _parse_route_line(self, line: str) -> Optional[Dict[str, Any]]:
        """Parse a single BGP route line.
        
        Args:
            line: BGP route line from show command output
            
        Returns:
            Route dictionary or None if parsing fails
        """
        pattern = r'^\*>\s+(\S+)\s+(\S+)\s+(\d+)\s+(\d+)\s+(.+)$'
        match = re.match(pattern, line)
        if not match:
            return None
            
        network, next_hop, metric_str, weight_str, path_info = match.groups()
        
        try:
            return {
                "network": self._normalize_network_cidr(network),
                "nextHopIp": next_hop,
                "med": int(metric_str),
                "localPref": 100, # Always 100 for learned routes on PEs
                "weight": int(weight_str),
                "asPath": self._parse_as_path(path_info)
            }
        except ValueError as e:
            logging.warning(f"Failed to parse route line '{line}': {e}")
            return None

    def _find_route_start_index(self, lines: List[str]) -> Optional[int]:
        """Find the index where BGP routes start in the output.
        
        Args:
            lines: List of output lines
            
        Returns:
            Index of first route line or None if not found
        """
        for i, line in enumerate(lines):
            if 'Network' in line and 'Next Hop' in line:
                return i + 1
        return None

    def _get_all_bgp_routes(self) -> Dict[str, List[Dict[str, Any]]]:
        """Parse BGP route table output and return structured data.
        
        Returns:
            Dictionary containing list of BGP routes
        """
        try:
            output = """BGP table version is 0, local router ID is 169.254.112.97
Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,
            r RIB-failure, S Stale, R Removed
Origin codes: i - IGP, e - EGP, ? - incomplete

Network          Next Hop            Metric LocPrf Weight Path
*> 0.0.0.0          169.254.112.98        0             0 65000 i
*> 172.16.0.1/32    169.254.112.98        0             0 65000 i
*> 172.16.0.2/32    169.254.112.98        0             0 65000 65114 49449 i
*> 172.16.0.3/32    169.254.112.98        0             0 65000 i
*> 172.16.0.4/32    169.254.112.98        0             0 65000 i
*> 172.16.0.5/32    169.254.112.98        0             0 65000 i
*> 172.16.0.112/32  169.254.112.98        0             0 65000 i
*> 172.16.0.113/32  169.254.112.98        0             0 65000 i
*> 172.16.0.114/32  169.254.112.98        0             0 65000 i
*> 172.16.0.115/32  169.254.112.98        0             0 65000 i
*> 172.16.0.116/32  169.254.112.98        0             0 65000 i
*> 172.16.0.117/32  169.254.112.98        0             0 65000 i
*> 172.16.0.118/32  169.254.112.98        0             0 65000 i
*> 172.16.0.119/32  169.254.112.98        0             0 65000 i
*> 172.16.0.120/32  169.254.112.98        0             0 65000 i
*> 172.16.0.121/32  169.254.112.98        0             0 65000 i
*> 172.31.0.0       169.254.112.97        100           32768 i
*> 172.0.0.0        169.254.112.97        100           32768 i
*> 172.1.1.0        169.254.112.97        100           32768 i
*> 172.31.0.1/32    169.254.112.97        100           32768 i
*> 172.31.0.2/32    169.254.112.97        100           32768 i
*> 172.31.0.3/32    169.254.112.97        100           32768 i
*> 172.31.0.4/32    169.254.112.97        100           32768 i
*> 2001:db8:2::/64  fe80::2               100           32768 i
*> 2001:db8:2::1/128 fe80::2              100           32768 i
*> 2001:db8:2::2/128 fe80::2              100           32768 i
*> 2001:db8:2::3/128 fe80::2              100           32768 i
*> 2001:db8:2::4/128 fe80::2              100           32768 i

Total number of prefixes 3233"""
            
            # Check if command output is valid
            if not output or not output.strip():
                logging.warning("BGP command returned empty output")
                return {"routes": []}
            
            lines = output.strip().split('\n')
            route_start_idx = self._find_route_start_index(lines)
            
            if route_start_idx is None:
                logging.warning("BGP output does not contain expected header format")
                return {"routes": []}
            
            # Parse routes using list comprehension and filter
            route_lines = [
                line.strip() for line in lines[route_start_idx:]
                if line.strip() and line.strip().startswith('*>') 
                and not line.strip().startswith('Total number')
            ]
            
            # Parse routes and convert to dictionaries
            routes = []
            for line in route_lines:
                route = self._parse_route_line(line)
                if route is not None:
                    routes.append(route)
            
            return {"routes": routes}
            
        except Exception as e:
            logging.error(f"Failed to get BGP routes: {e}")
            return {"routes": []}
    
    def get_specific_network(self, bgp_properties: Dict[str, Any], prefix: str) -> Dict[str, Any]:
        """Find specific network in BGP properties.
        
        Args:
            bgp_properties: BGP properties dictionary
            prefix: Network prefix to search for
            
        Returns:
            Route information dictionary or empty dict if not found
        """
        if not bgp_properties or not isinstance(bgp_properties, dict):
            logging.warning(f"Invalid BGP properties: {type(bgp_properties)}")
            return {}
            
        routes = bgp_properties.get("routes", [])
        logging.debug(f"Searching for prefix '{prefix}' in {len(routes)} routes")
        
        # Use next() with generator expression for efficient search
        try:
            route = next(
                route for route in routes 
                if route.get("network") == prefix
            )
            logging.debug(f"Found matching route for prefix '{prefix}': {route}")
            return route
        except StopIteration:
            logging.debug(f"No route found for prefix '{prefix}'")
            return {}


def main():
    """Main function to demonstrate BGP router functionality."""
    router = BGPRouter()
    
    # Get all BGP routes
    bgp_routes = router._get_all_bgp_routes()
    print(f"Parsed {len(bgp_routes['routes'])} BGP routes")
    print(bgp_routes)
    
    # # Display first few routes
    # for i, route in enumerate(bgp_routes['routes'][:3]):
    #     print(f"Route {i+1}: {route}")
    
    # # Search for specific prefix
    # specific_prefix = "172.16.0.1/32"
    # route_info = router.get_specific_network(bgp_routes, specific_prefix)
    
    # if route_info:
    #     print(f"Found route for {specific_prefix}: {route_info}")
    # else:
    #     print(f"No route found for {specific_prefix}")


if __name__ == "__main__":
    main()
class ProposalParser:
    """A class to parse IKE and ESP proposal strings into human-readable formats.

    This class supports parsing of IKE and ESP proposals, extracting encryption, hash, PRF (for IKE),
    and Diffie-Hellman (DH) group information. It also handles the concatenation of these components
    into a structured format, indicating whether Perfect Forward Secrecy (PFS) is enabled for ESP proposals.
    The parser uses predefined mappings for DH groups, encryption algorithms, hash functions, and Pseudo-Random Functions (PRFs).
    It can process a list of proposals and return a formatted string summarizing the cryptographic parameters.
    Attributes:

        dh_mapping (dict): A mapping of Diffie-Hellman groups to their corresponding identifiers

        enc_mapping (dict): A mapping of encryption algorithms to their corresponding identifiers

        hash_mapping (dict): A mapping of hash functions to their corresponding identifiers

        prf_mapping (dict): A mapping of Pseudo-Random Functions to their corresponding identifiers

    Methods:
        parse_ike_proposal(proposal): Parses a single IKE or ESP proposal string into a structured dictionary with encryption, hash, PRF, and DH group information.

        process_proposals(proposal_list): Processes a comma-separated list of IKE or ESP proposals, concatenating encryption, hash, PRF (for IKE), and DH group values, and indicating whether PFS is enabled for ESP proposals.
    
    Usage:
        _proposal_parser = ProposalParser()
        proposal = "IKE:AES_CBC_256/HMAC_SHA2_256/PRF_HMAC_SHA2_256/MODP_2048"
        parsed_proposal = _proposal_parser.parse_ike_proposal(proposal)
        print(parsed_proposal)
        # Output: {'encryption': ['AES256'], 'hash': ['SHA2-256'], 'prf': ['SHA2-256'], 'dh_group': ['14']}
        proposal_list = "IKE:AES_CBC_256/HMAC_SHA2_256/PRF_HMAC_SHA2_256/MODP_2048, ESP:AES_GCM_16_256/HMAC_SHA2_256/MODP_2048"
        formatted_proposal = _proposal_parser.process_proposals(proposal_list)
        print(formatted_proposal)ss
        # Output: "Encryption: AES256, AES128-GCM-16 Hash: SHA2-256, PRF: SHA2-256, DH Group(s): 14 PFS: Enabled"
    """
    
    def __init__(self):
        """Initialize the parser with mappings for DH groups, encryption, hash, and PRF."""
        self.dh_mapping = {
            'MODP_768': '1',
            'MODP_1024': '2',
            'MODP_1536': '5',
            'MODP_2048': '14',
            'MODP_3072': '15',
            'MODP_4096': '16',
            'MODP_6144': '17',
            'MODP_8192': '18',
            'ECP_256': '19',
            'ECP_384': '20',
            'ECP_521': '21',
            'ECP_192': '25',
            'ECP_224': '26',
            'MODP_1024_160': '22',
            'MODP_2048_224': '23',
            'MODP_2048_256': '24',
            'FFDHE_2048': '256',
            'FFDHE_3072': '257',
            'FFDHE_4096': '258',
            'FFDHE_6144': '259',
            'FFDHE_8192': '260',
            'ECP_224_BP': '27',
            'ECP_256_BP': '28',
            'ECP_384_BP': '29',
            'ECP_512_BP': '30',
            'CURVE_25519': '31',
            'CURVE_448': '32',
        }
        
        self.enc_mapping = {
            'AES_CBC_128': 'AES128',
            'AES_CBC_192': 'AES192',
            'AES_CBC_256': 'AES256',
            'AES_GCM_16_128': 'AES128-GCM-16',
            'AES_GCM_16_192': 'AES192-GCM-16',
            'AES_GCM_16_256': 'AES256-GCM-16',
            'AES_GCM_8_128': 'AES128-GCM-8',
            'AES_GCM_8_256': 'AES256-GCM-8',
            'AES_GCM_12_128': 'AES128-GCM-12',
            'AES_GCM_12_256': 'AES256-GCM-12',
            'AES_CCM_16_128': 'AES128-CCM-16',
            'AES_CCM_16_256': 'AES256-CCM-16',
            'AES_CTR_128': 'AES128-CTR',
            'AES_CTR_192': 'AES192-CTR',
            'AES_CTR_256': 'AES256-CTR',
            '3DES_CBC': '3DES',
            'DES_CBC': 'DES',
            'CAMELLIA_CBC_128': 'CAMELLIA128',
            'CAMELLIA_CBC_256': 'CAMELLIA256',
            'CHACHA20_POLY1305': 'CHACHA20-POLY1305',
            'BLOWFISH_CBC': 'BLOWFISH',
            'CAST5_CBC': 'CAST5'
        }
        
        self.hash_mapping = {
            'HMAC_MD5': 'MD5',
            'HMAC_MD5_96': 'MD5',
            'HMAC_SHA1': 'SHA1',
            'HMAC_SHA1_96': 'SHA1',
            'HMAC_SHA2_256': 'SHA2-256',
            'HMAC_SHA2_256_128': 'SHA2-256',
            'HMAC_SHA2_384': 'SHA2-384',
            'HMAC_SHA2_384_192': 'SHA2-384',
            'HMAC_SHA2_512': 'SHA2-512',
            'HMAC_SHA2_512_256': 'SHA2-512',
            'HMAC_SHA3_224': 'SHA3-224',
            'HMAC_SHA3_256': 'SHA3-256',
            'HMAC_SHA3_384': 'SHA3-384',
            'HMAC_SHA3_512': 'SHA3-512',
            'AES_GMAC_128': 'GMAC-128',
            'AES_GMAC_192': 'GMAC-192',
            'AES_GMAC_256': 'GMAC-256',
            'POLY1305': 'POLY1305'
        }
        
        self.prf_mapping = {
            'PRF_HMAC_MD5': 'MD5',
            'PRF_HMAC_SHA1': 'SHA1',
            'PRF_HMAC_SHA2_256': 'SHA2-256',
            'PRF_HMAC_SHA2_384': 'SHA2-384',
            'PRF_HMAC_SHA2_512': 'SHA2-512',
            'PRF_AES128_CMAC': 'AES128-CMAC',
            'PRF_AES128_XCBC': 'AES128-XCBC',
            'PRF_HMAC_SHA3_224': 'SHA3-224',
            'PRF_HMAC_SHA3_256': 'SHA3-256',
            'PRF_HMAC_SHA3_384': 'SHA3-384',
            'PRF_HMAC_SHA3_512': 'SHA3-512'
        }

    def parse_ike_proposal(self, proposal):
        """
        Parse an IKE or ESP proposal string into a structured format.

        Args:
            proposal (str): The proposal string, e.g., "IKE:AES_CBC_256/HMAC_SHA2_256/PRF_HMAC_SHA2_256/MODP_2048"
            
        Returns:
            dict: A dictionary with keys 'encryption', 'hash', 'prf', and 'dh_group'
        """

        # Split the proposal into components based on '/'
        components = proposal.split('/')
        
        result = {
            'encryption': [],
            'hash': [],
            'prf': [],
            'dh_group': []
        }
        
        
        is_ike = proposal.startswith('IKE:')
        is_esp = proposal.startswith('ESP:')
        

        # Remove IKE or ESP prefix if present for easier parsing later
        if is_ike or is_esp:
            components[0] = components[0].replace('IKE:', '').replace('ESP:', '')
        

        enc_components = []
        hash_components = []
        prf_components = []
        dh_components = []

        
        # Determine the current section based on the first component
        current_section = 'enc'
        for component in components:
            if component in self.enc_mapping:
                if current_section != 'enc':
                    current_section = 'enc'
                enc_components.append(component)
            elif component in self.hash_mapping:
                if current_section != 'hash':
                    current_section = 'hash'
                hash_components.append(component)
            elif is_ike and 'PRF_' in component:
                if current_section != 'prf':
                    current_section = 'prf'
                prf_components.append(component)
            elif component in self.dh_mapping:
                if current_section != 'dh':
                    current_section = 'dh'
                dh_components.append(component)
            elif component == 'NO_EXT_SEQ':
                continue  # Skip NO_EXT_SEQ as it’s not relevant to crypto algorithms
        

        # Map encryption components
        for enc in enc_components:
            mapped_enc = self.enc_mapping.get(enc, 'Unknown')
            if mapped_enc != 'Unknown' and mapped_enc not in result['encryption']:
                result['encryption'].append(mapped_enc)
        
        # Map hash components (skip for AEAD ciphers like AES-GCM)
        if not any(enc.startswith('AES_GCM') or enc.startswith('AES_CCM') or enc == 'CHACHA20_POLY1305' for enc in enc_components):
            for hash_val in hash_components:
                mapped_hash = self.hash_mapping.get(hash_val, 'Unknown')
                if mapped_hash != 'Unknown' and mapped_hash not in result['hash']:
                    result['hash'].append(mapped_hash)
        else:
            result['hash'] = ['None']

        
        # Map PRF components
        for prf in prf_components:
            mapped_prf = self.prf_mapping.get(prf, 'Unknown')
            if mapped_prf == "Unknown":
                result['prf'].append(mapped_prf)
            if mapped_prf != 'Unknown' and mapped_prf not in result['prf']:
                result['prf'].append(mapped_prf)


        # Map DH group components
        for dh in dh_components:
            mapped_dh = self.dh_mapping.get(dh)
            if mapped_dh != 'None' and mapped_dh not in result['dh_group']:
                result['dh_group'].append(mapped_dh)

        
        # Handle ESP case (no PRF for ESP proposals)
        if is_esp:
            result['prf'] = ['None']
        
        if not result['encryption']:
            result['encryption'] = ['Unknown']

        if not result['hash']:
            result['hash'] = ['Unknown']

        return result

    def process_proposals(self, proposal_list):
        """
        Process a list of IKE or ESP proposals, concatenating encryption, hash, PRF (for IKE only), 
        and DH group values, and indicate whether PFS is enabled for ESP proposals only.
        
        Args:
            proposal_list (str): Comma-separated string of IKE or ESP proposals
        
        Returns:
            str: Formatted string with concatenated encryption, hash, PRF (for IKE), DH groups, and PFS status (for ESP)
        """
        proposal_list = proposal_list.replace(',', ', ')
        proposals = proposal_list.strip().split(', ')

        
        # Collect unique encryption, hash, PRF, and DH groups
        enc_set = set()
        hash_set = set()
        prf_set = set()
        dh_set = set()


        # Parse each proposal and update the sets for later sorting and formatting
        for proposal in proposals:
            parsed = self.parse_ike_proposal(proposal.strip())
            enc_set.update(parsed['encryption'])
            if parsed['hash'] != ['None']:
                hash_set.update(parsed['hash'])
            if parsed['prf'] != ['None']:
                prf_set.update(parsed['prf'])
            if parsed['dh_group'] != ['None']:
                dh_set.update(parsed['dh_group'])

        
        # Convert sets to sorted lists
        enc_list = sorted(list(enc_set))
        hash_list = sorted(list(hash_set))
        prf_list = sorted(list(prf_set))
        dh_list = sorted(list(dh_set), key=lambda x: int(x))

        
        # Determine PFS status for ESP proposals only
        is_ike = any(proposal.startswith('IKE:') for proposal in proposals)
        pfs_status = "PFS: Enabled" if dh_set and not is_ike else "PFS: None"

        
        # Format output as a single concatenated string
        enc_part = f"Encryption: {', '.join(enc_list)}" if enc_list else "Encryption: None"
        hash_part = f"Hash: {', '.join(hash_list)}" if hash_list else "Hash: None"
        dh_part = f"DH Group(s): {', '.join(dh_list)}" if dh_list else "DH Group(s): None"
        prf_part = f"PRF: {', '.join(prf_list)}" if prf_list else "PRF: None"

        
        # Return formatted string based on whether it's an IKE or ESP proposal
        if is_ike:
            return f"{enc_part} {hash_part} {prf_part} {dh_part}"
        else:
            return f"{enc_part} {hash_part} {dh_part} {pfs_status}"
            
# Example usage
if __name__ == "__main__":
    parser = ProposalParser()

    #IKEV1 PROPOSALS AWS DEFAULT
    ikev1_default_proposals = """IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_1024, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_2048, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_3072, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_4096, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_6144, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_8192, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/ECP_256, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/ECP_384, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/ECP_521, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_1024_160, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_2048_224, IKE:AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_2048_256, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_1024, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_2048, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_3072, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_4096, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_6144, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_8192, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/ECP_256, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/ECP_384, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/ECP_521, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_1024_160, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_2048_224, IKE:AES_CBC_128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_2048_256, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_1024, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_2048, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_3072, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_4096, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_6144, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_8192, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/ECP_256, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/ECP_384, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/ECP_521, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_1024_160, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_2048_224, IKE:AES_CBC_128/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_2048_256, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_1024, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_2048, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_3072, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_4096, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_6144, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_8192, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/ECP_256, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/ECP_384, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/ECP_521, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_1024_160, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_2048_224, IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_2048_256, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_1024, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_2048, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_3072, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_4096, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_6144, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_8192, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/ECP_256, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/ECP_384, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/ECP_521, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_1024_160, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_2048_224, IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_2048_256, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_1024, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_2048, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_3072, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_4096, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_6144, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_8192, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/ECP_256, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/ECP_384, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/ECP_521, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_1024_160, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_2048_224, IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_2048_256, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_1024, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_2048, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_3072, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_4096, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_6144, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_8192, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/ECP_256, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/ECP_384, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/ECP_521, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_1024_160, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_2048_224, IKE:AES_CBC_256/HMAC_SHA2_384_192/PRF_HMAC_SHA2_384/MODP_2048_256, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_1024, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_2048, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_3072, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_4096, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_6144, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_8192, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/ECP_256, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/ECP_384, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/ECP_521, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_1024_160, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_2048_224, IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_2048_256"""

    #ESP Phase 2 proposals example AWS DEFAULT
    ikev1_default_esp_proposals = """ESP:AES_CBC_128/HMAC_SHA1_96/MODP_1024/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA1_96/MODP_1536/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA1_96/MODP_2048/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA1_96/MODP_3072/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA1_96/MODP_4096/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA1_96/MODP_6144/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA1_96/MODP_8192/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA1_96/ECP_256/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA1_96/ECP_384/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA1_96/ECP_521/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA1_96/MODP_1024_160/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA1_96/MODP_2048_224/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA1_96/MODP_2048_256/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_256_128/MODP_1024/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_256_128/MODP_1536/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_256_128/MODP_2048/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_256_128/MODP_3072/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_256_128/MODP_4096/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_256_128/MODP_6144/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_256_128/MODP_8192/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_256_128/ECP_256/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_256_128/ECP_384/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_256_128/ECP_521/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_256_128/MODP_1024_160/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_256_128/MODP_2048_224/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_256_128/MODP_2048_256/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_384_192/MODP_1024/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_384_192/MODP_1536/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_384_192/MODP_2048/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_384_192/MODP_3072/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_384_192/MODP_4096/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_384_192/MODP_6144/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_384_192/MODP_8192/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_384_192/ECP_256/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_384_192/ECP_384/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_384_192/ECP_521/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_384_192/MODP_1024_160/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_384_192/MODP_2048_224/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_384_192/MODP_2048_256/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_512_256/MODP_1024/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_512_256/MODP_1536/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_512_256/MODP_2048/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_512_256/MODP_3072/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_512_256/MODP_4096/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_512_256/MODP_6144/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_512_256/MODP_8192/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_512_256/ECP_256/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_512_256/ECP_384/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_512_256/ECP_521/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_512_256/MODP_1024_160/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_512_256/MODP_2048_224/NO_EXT_SEQ, ESP:AES_CBC_128/HMAC_SHA2_512_256/MODP_2048_256/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA1_96/MODP_1024/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA1_96/MODP_1536/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA1_96/MODP_2048/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA1_96/MODP_3072/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA1_96/MODP_4096/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA1_96/MODP_6144/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA1_96/MODP_8192/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA1_96/ECP_256/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA1_96/ECP_384/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA1_96/ECP_521/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA1_96/MODP_1024_160/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA1_96/MODP_2048_224/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA1_96/MODP_2048_256/NO_EXT_SEQ,ESP:AES_CBC_256/HMAC_SHA2_256_128/MODP_1024/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_256_128/MODP_1536/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_256_128/MODP_2048/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_256_128/MODP_3072/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_256_128/MODP_4096/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_256_128/MODP_6144/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_256_128/MODP_8192/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_256_128/ECP_256/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_256_128/ECP_384/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_256_128/ECP_521/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_256_128/MODP_1024_160/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_256_128/MODP_2048_224/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_256_128/MODP_2048_256/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_384_192/MODP_1024/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_384_192/MODP_1536/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_384_192/MODP_2048/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_384_192/MODP_3072/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_384_192/MODP_4096/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_384_192/MODP_6144/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_384_192/MODP_8192/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_384_192/ECP_256/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_384_192/ECP_384/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_384_192/ECP_521/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_384_192/MODP_1024_160/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_384_192/MODP_2048_224/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_384_192/MODP_2048_256/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_512_256/MODP_1024/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_512_256/MODP_1536/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_512_256/MODP_2048/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_512_256/MODP_3072/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_512_256/MODP_4096/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_512_256/MODP_6144/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_512_256/MODP_8192/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_512_256/ECP_256/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_512_256/ECP_384/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_512_256/ECP_521/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_512_256/MODP_1024_160/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_512_256/MODP_2048_224/NO_EXT_SEQ, ESP:AES_CBC_256/HMAC_SHA2_512_256/MODP_2048_256/NO_EXT_SEQ, ESP:AES_GCM_16_128/MODP_1024/NO_EXT_SEQ, ESP:AES_GCM_16_128/MODP_1536/NO_EXT_SEQ, ESP:AES_GCM_16_128/MODP_2048/NO_EXT_SEQ, ESP:AES_GCM_16_128/MODP_3072/NO_EXT_SEQ, ESP:AES_GCM_16_128/MODP_4096/NO_EXT_SEQ, ESP:AES_GCM_16_128/MODP_6144/NO_EXT_SEQ, ESP:AES_GCM_16_128/MODP_8192/NO_EXT_SEQ, ESP:AES_GCM_16_128/ECP_256/NO_EXT_SEQ, ESP:AES_GCM_16_128/ECP_384/NO_EXT_SEQ, ESP:AES_GCM_16_128/ECP_521/NO_EXT_SEQ, ESP:AES_GCM_16_128/MODP_1024_160/NO_EXT_SEQ, ESP:AES_GCM_16_128/MODP_2048_224/NO_EXT_SEQ, ESP:AES_GCM_16_128/MODP_2048_256/NO_EXT_SEQ, ESP:AES_GCM_16_256/MODP_1024/NO_EXT_SEQ, ESP:AES_GCM_16_256/MODP_1536/NO_EXT_SEQ, ESP:AES_GCM_16_256/MODP_2048/NO_EXT_SEQ, ESP:AES_GCM_16_256/MODP_3072/NO_EXT_SEQ, ESP:AES_GCM_16_256/MODP_4096/NO_EXT_SEQ, ESP:AES_GCM_16_256/MODP_6144/NO_EXT_SEQ, ESP:AES_GCM_16_256/MODP_8192/NO_EXT_SEQ, ESP:AES_GCM_16_256/ECP_256/NO_EXT_SEQ, ESP:AES_GCM_16_256/ECP_384/NO_EXT_SEQ, ESP:AES_GCM_16_256/ECP_521/NO_EXT_SEQ, ESP:AES_GCM_16_256/MODP_1024_160/NO_EXT_SEQ, ESP:AES_GCM_16_256/MODP_2048_224/NO_EXT_SEQ, ESP:AES_GCM_16_256/MODP_2048_256/NO_EXT_SEQ"""

    #IKEV2 PROPOSALS AWS DEFAULT
    ikev2_default_proposals = """IKE:AES_CBC_128/AES_CBC_256/HMAC_SHA1_96/HMAC_SHA2_256_128/HMAC_SHA2_384_192/HMAC_SHA2_512_256/PRF_HMAC_SHA1/PRF_HMAC_SHA2_256/PRF_HMAC_SHA2_384/PRF_HMAC_SHA2_512/MODP_1024/MODP_2048/MODP_3072/MODP_4096/MODP_6144/MODP_8192/ECP_256/ECP_384/ECP_521/MODP_1024_160/MODP_2048_224/MODP_2048_256, IKE:AES_GCM_16_128/AES_GCM_16_256/PRF_HMAC_SHA1/PRF_HMAC_SHA2_256/PRF_HMAC_SHA2_384/PRF_HMAC_SHA2_512/MODP_1024/MODP_2048/MODP_3072/MODP_4096/MODP_6144/MODP_8192/ECP_256/ECP_384/ECP_521/MODP_1024_160/MODP_2048_224/MODP_2048_256"""

    #ESP PROPOSALS Phase 2 AWS DEFAULT 
    #ikev2_default_esp_proposals = """IKE:AES_CBC_256/HMAC_SHA1_96/PRF_INVALID/MODP_2048"""
    ikev2_default_esp_proposals = """IKE:AES_CBC_128/AES_CBC_256/HMAC_SHA1_96/HMAC_SHA2_256_128/HMAC_SHA2_384_192/HMAC_SHA2_512_256/PRF_HMAC_SHA1/PRF_HMAC_SHA2_256/PRF_HMAC_SHA2_384/PRF_HMAC_SHA2_512/MODP_1024/MODP_2048/MODP_3072/MODP_4096/MODP_6144/MODP_8192/ECP_256/ECP_384/ECP_521/MODP_1024_160/MODP_2048_224/MODP_2048_256, IKE:AES_GCM_16_128/AES_GCM_16_256/PRF_HMAC_SHA1/PRF_HMAC_SHA2_256/PRF_HMAC_SHA2_384/PRF_HMAC_SHA2_512/MODP_1024/MODP_2048/MODP_3072/MODP_4096/MODP_6144/MODP_8192/ECP_256/ECP_384/ECP_521/MODP_1024_160/MODP_2048_224/MODP_2048_256"""
    #ikev2_default_esp_proposals = """IKE:AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_2048"""
    #proposal = "IKE:AES_CBC_128/AES_CBC_256/HMAC_SHA1_96/HMAC_SHA2_256_128/HMAC_SHA2_384_192/HMAC_SHA2_512_256/PRF_HMAC_SHA1/PRF_HMAC_SHA2_256/PRF_HMAC_SHA2_384/PRF_HMAC_SHA2_512/MODP_1024/MODP_2048/MODP_3072/MODP_4096/MODP_6144/MODP_8192/ECP_256/ECP_384/ECP_521/MODP_1024_160/MODP_2048_224/MODP_2048_256, IKE:AES_GCM_16_128/AES_GCM_16_256/PRF_HMAC_SHA1/PRF_HMAC_SHA2_256/PRF_HMAC_SHA2_384/PRF_HMAC_SHA2_512/MODP_1024/MODP_2048/MODP_3072/MODP_4096/MODP_6144/MODP_8192/ECP_256/ECP_384/ECP_521/MODP_1024_160/MODP_2048_224/MODP_2048_256"
    proposal = """
    
    testing = """IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_2048,IKE:AES_CBC_128/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/MODP_3072"""
    # print(f'IKEv1 AWS DEFAULT PROPOSALS\n{parser.process_proposals(ikev1_default_proposals)}')
    # print(f'\n\nIKEv2 AWS DEFAULT PROPOSALS\n{parser.process_proposals(ikev2_default_proposals)}')
    # print(f'\n\nIKEv1 ESP PROPOSALS AWS DEFAULT\n{parser.process_proposals(ikev1_default_esp_proposals)}')
    print(f'\n\nIKEv2 ESP PROPOSALS AWS DEFAULT\n{parser.process_proposals(proposal)}')
import subprocess
import json
import re


def parse_bgp_routes(bgp_output):
    """
    Parse BGP route table output and return structured data.
    
    Args:
        bgp_output (str): Raw BGP table output
        
    Returns:
        dict: Structured BGP routes data
    """
    routes = []
    
    # Split into lines and find the route entries
    lines = bgp_output.strip().split('\n')
    
    # Find the header line to identify where routes start
    route_start_idx = None
    for i, line in enumerate(lines):
        if 'Network' in line and 'Next Hop' in line:
            route_start_idx = i + 1
            break
    
    if route_start_idx is None:
        return {"routes": routes}
    
    # Parse each route line
    for line in lines[route_start_idx:]:
        line = line.strip()
        
        # Skip empty lines and summary lines
        if not line or line.startswith('Total number') or line.startswith('IPv6'):
            continue
            
        # Skip lines that don't start with route status indicators
        if not line.startswith('*>'):
            continue
        
        # Parse the route line using regex
        # Pattern matches: *> network next_hop metric [locprf] weight path
        # Note: LocPrf column may be empty, so we'll set it to 0 for all records
        pattern = r'^\*>\s+(\S+)\s+(\S+)\s+(\d+)\s+(\d+)\s+(.+)$'
        match = re.match(pattern, line)
        
        if match:
            network = match.group(1)
            next_hop = match.group(2)
            metric = int(match.group(3))
            loc_prf = 0  # Set to 0 for all records as requested
            weight = int(match.group(4))
            path_info = match.group(5).strip()
            
            # Extract AS path (remove origin code)
            path_parts = path_info.split()
            as_path = []
            for part in path_parts:
                if part.isdigit():
                    as_path.append(part)
            
            path = ' '.join(as_path) if as_path else ""
            
            route = {
                "network": network,
                "nextHop": next_hop,
                "metric": metric,
                "locPrf": loc_prf,
                "weight": weight,
                "path": path
            }
            routes.append(route)
    
    return {"routes": routes}


def get_bgp_routes_json():
    """
    Get BGP routes from sample data and return as JSON.
    
    Returns:
        str: JSON string of BGP routes
    """
    output_text = """IPv4
BGP table version is 0, local router ID is 169.254.0.185
Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,
            r RIB-failure, S Stale, R Removed
Origin codes: i - IGP, e - EGP, ? - incomplete

Network          Next Hop            Metric LocPrf Weight Path
*> 10.0.0.0         169.254.0.186          100             0 65100 ?
*> 10.2.0.0/16      169.254.0.185          100         32768 i
*> 10.5.0.0/16      169.254.0.185          100         32768 i
*> 10.6.0.0/16      169.254.0.185          100         32768 i
*> 10.10.0.0/16     169.254.0.185          100         32768 i
*> 10.42.0.0/16     169.254.0.185          100         32768 i
*> 10.56.0.0/16     169.254.0.185          100         32768 i
*> 10.133.0.0/21    169.254.0.185          100         32768 i
*> 10.192.2.0/23    169.254.0.186          100             0 65100 ?
*> 10.192.6.0/23    169.254.0.186          100             0 65100 ?
*> 10.208.0.0/18    169.254.0.185          100         32768 i
*> 10.210.0.0/20    169.254.0.186          100             0 65100 ?
*> 10.210.64.0/18   169.254.0.186          100             0 65100 ?
*> 10.210.128.0/20  169.254.0.186          100             0 65100 ?
*> 10.211.0.0/17    169.254.0.186          100             0 65100 ?
*> 10.211.128.0/17  169.254.0.186          100             0 65100 ?
*> 10.216.0.0/16    169.254.0.186          100             0 65100 ?
*> 10.224.64.0/19   169.254.0.185          100         32768 i
*> 10.227.128.0/18  169.254.0.185          100         32768 i
*> 10.227.192.0/18  169.254.0.185          100         32768 i
*> 10.228.64.0/18   169.254.0.185          100         32768 i
*> 10.228.128.0/18  169.254.0.185          100         32768 i
*> 10.228.192.0/18  169.254.0.185          100         32768 i
*> 10.229.64.0/18   169.254.0.185          100         32768 i
*> 10.229.128.0/18  169.254.0.185          100         32768 i
*> 10.229.192.0/18  169.254.0.185          100         32768 i
*> 10.230.0.0/18    169.254.0.185          100         32768 i
*> 10.230.64.0/18   169.254.0.185          100         32768 i
*> 10.230.128.0/18  169.254.0.185          100         32768 i
*> 10.230.192.0/18  169.254.0.185          100         32768 i
*> 10.246.48.0/20   169.254.0.185          100         32768 i
*> 10.254.192.0/18  169.254.0.185          100         32768 i
*> 10.255.0.0/18    169.254.0.185          100         32768 i
*> 10.255.64.0/18   169.254.0.185          100         32768 i
*> 10.255.128.0/18  169.254.0.185          100         32768 i
*> 10.255.192.0/19  169.254.0.185          100         32768 i
*> 10.255.224.0/19  169.254.0.185          100         32768 i
*> 100.64.0.64/27   169.254.0.185          100         32768 i
*> 100.64.0.96/27   169.254.0.185          100         32768 i
*> 100.64.0.128/27  169.254.0.185          100         32768 i
*> 100.64.0.160/27  169.254.0.185          100         32768 i
*> 172.16.0.0/12    169.254.0.186          100             0 65100 69999 21222 ?
*> 240.0.0.0/4      169.254.0.186          100             0 65100 69999 21222 ?
*> 253.128.0.0/14   169.254.0.186          100             0 65100 ?
*> 253.132.0.0/20   169.254.0.186          100             0 65100 ?

Total number of prefixes 45

IPv6
No BGP network exists"""
    
    # Parse the BGP output and return as JSON
    parsed_data = parse_bgp_routes(output_text)
    return json.dumps(parsed_data, indent=2)

def get_specific_network(prefix):
    # Get all BGP routes first
    all_routes = json.loads(get_bgp_routes_json())
    
    # Search through routes for matching prefix
    for route in all_routes["routes"]:
        if route["network"] == prefix:
            return route
            
    # Return None if no matching prefix is found
    return None

def main():
    """Main function to demonstrate the BGP parser."""
    print(get_bgp_routes_json())
    print(get_specific_network("10.42.0.0/16"))


if __name__ == "__main__":
    main()