Example #1
0
    def create_network_isolation_rules(self):

        rules = list()
        transport_list = list()

        _logger.debug('{0}: adding network isolation rules.'.format(self.get_name()))

        for cidr in self._allowed_networks.split(' '):

            cidr = cidr.encode('utf-8')

            if not validate_network_address(cidr):
                _logger.error('{0} unable to validate network cidr value "{1}"'.format(self.get_name(), cidr))
                continue

            # Get IP transport version from address.
            ipaddr, bits = cidr.split('/')
            transport = check_transport_value(ipaddr, ipt.TRANSPORT_AUTO)

            # Save the transports we use so we can add the reject rules later.
            if transport not in transport_list:
                transport_list.append(transport)

            rules.append(ipt.get_machine_subset(
                "network iso",
                Slots.network_iso,
                [
                    ipt.get_chain(
                        u'filter',
                        [
                            ipt.get_ring(
                                u'input',
                                transport,
                                [
                                    ipt.get_rule(source_address=cidr, jump=ipt.get_jump(target=u'RETURN'))
                                ]
                            ),
                            ipt.get_ring(
                                u'output',
                                transport,
                                [
                                    ipt.get_rule(dest_address=cidr, jump=ipt.get_jump(target=u'RETURN'))
                                ]
                            ),
                        ]
                    )
                ]
            ))

        # Create network isolation rejection rules.
        for transport in transport_list:
            rules.append(create_iptables_ingress_egress_reject_rule(Slots.network_iso, transport, 'iso reject'))

        return rules
    def create_network_isolation_rules(self):

        rules = list()
        transport_list = list()

        _logger.debug('{0}: adding network isolation rules.'.format(self.get_name()))

        for cidr in self._allowed_networks.split(' '):

            cidr = cidr.encode('utf-8')

            if not validate_network_address(cidr):
                _logger.error('{0} unable to validate network cidr value "{1}"'.format(self.get_name(), cidr))
                continue

            # Get IP transport version from address.
            ipaddr, bits = cidr.split('/')
            transport = check_transport_value(ipaddr, ipt.TRANSPORT_AUTO)

            # Save the transports we use so we can add the reject rules later.
            if transport not in transport_list:
                transport_list.append(transport)

            rules.append(ipt.get_machine_subset(
                "network iso",
                Slots.network_iso,
                [
                    ipt.get_chain(
                        u'filter',
                        [
                            ipt.get_ring(
                                u'input',
                                transport,
                                [
                                    ipt.get_rule(source_address=cidr, jump=ipt.get_jump(target=u'RETURN'))
                                ]
                            ),
                            ipt.get_ring(
                                u'output',
                                transport,
                                [
                                    ipt.get_rule(dest_address=cidr, jump=ipt.get_jump(target=u'RETURN'))
                                ]
                            ),
                        ]
                    )
                ]
            ))

        # Create network isolation rejection rules.
        for transport in transport_list:
            rules.append(create_iptables_ingress_egress_reject_rule(Slots.network_iso, transport, 'iso reject'))

        return rules
    def create_logging_rules(self):

        rules = list()

        rules.append(
            ipt.get_machine_subset(u'ipv4 logging rule', 9800, [
                ipt.get_chain(u'filter', [
                    ipt.get_ring(u'output', ipt.TRANSPORT_IPV4, [
                        ipt.get_rule(matches=[
                            ipt.get_match('limit',
                                          options=[
                                              ipt.get_match_option(
                                                  '--limit', self._limit_rate),
                                          ]),
                        ],
                                     jump=ipt.get_jump(target=u'LOG',
                                                       params=[
                                                           ipt.get_jump_option(
                                                               u'--log-level',
                                                               value="alert"),
                                                           ipt.get_jump_option(
                                                               u'--log-prefix',
                                                               value=u'SDC: '),
                                                       ]))
                    ]),
                ])
            ]))

        rules.append(
            ipt.get_machine_subset(u'ipv4 logging rule', 9800, [
                ipt.get_chain(u'filter', [
                    ipt.get_ring(u'output', ipt.TRANSPORT_IPV6, [
                        ipt.get_rule(matches=[
                            ipt.get_match('limit',
                                          options=[
                                              ipt.get_match_option(
                                                  '--limit', self._limit_rate),
                                          ]),
                        ],
                                     jump=ipt.get_jump(target=u'LOG',
                                                       params=[
                                                           ipt.get_jump_option(
                                                               u'--log-level',
                                                               value="alert"),
                                                           ipt.get_jump_option(
                                                               u'--log-prefix',
                                                               value=u'SDC: '),
                                                       ]))
                    ]),
                ])
            ]))

        return rules
Example #4
0
def create_iptables_forward_reject_rule(slot, transport=ipt.TRANSPORT_AUTO, desc=''):
    """
    Create an firewall rule for all reject in FORWARD chain by default.
    :param slot: Firewall slot number
    :param transport: ipt.TRANSPORT_AUTO, ipt.TRANSPORT_IPV4 or ipt.TRANSPORT_IPV6
    :param desc: Extra description of the rule.
    :return:
    """

    if transport == ipt.TRANSPORT_AUTO:
        raise ValueError('Unable to determine transport')

    rule = ipt.get_rule(jump=ipt.get_jump(target=u'REJECT'))

    return ipt.get_machine_subset(
        desc,
        slot,
        [
            ipt.get_chain(
                u'filter',
                [
                    ipt.get_ring(
                        u'forward',
                        transport,
                        [
                            rule
                        ]
                    ),
                ]
            )
        ]
    )
def create_iptables_forward_reject_rule(slot, transport=ipt.TRANSPORT_AUTO, desc=''):
    """
    Create an firewall rule for all reject in FORWARD chain by default.
    :param slot: Firewall slot number
    :param transport: ipt.TRANSPORT_AUTO, ipt.TRANSPORT_IPV4 or ipt.TRANSPORT_IPV6
    :param desc: Extra description of the rule.
    :return:
    """

    if transport == ipt.TRANSPORT_AUTO:
        raise ValueError('Unable to determine transport')

    rule = ipt.get_rule(jump=ipt.get_jump(target=u'REJECT'))

    return ipt.get_machine_subset(
        desc,
        slot,
        [
            ipt.get_chain(
                u'filter',
                [
                    ipt.get_ring(
                        u'forward',
                        transport,
                        [
                            rule
                        ]
                    ),
                ]
            )
        ]
    )
Example #6
0
def create_iptables_icmp_all(slot, transport=ipt.TRANSPORT_AUTO, desc=''):
    """
    Create an rule for icmp traffic.
    :param slot: Firewall slot number
    :param transport: ipt.TRANSPORT_AUTO, ipt.TRANSPORT_IPV4 or ipt.TRANSPORT_IPV6
    :param desc: Extra description of the rule.
    :return:
    """

    if transport == ipt.TRANSPORT_AUTO:
        raise ValueError('Unable to determine transport for icmp')
    elif transport == ipt.TRANSPORT_IPV4:
        protocol = u'icmp'
    elif transport == ipt.TRANSPORT_IPV6:
        protocol = u'icmpv6'

    return ipt.get_machine_subset(
        desc,
        slot,
        [
            ipt.get_chain(
                u'filter',
                [
                    ipt.get_ring(
                        u'input',
                        transport,
                        [
                            ipt.get_rule(
                                ip_protocol_name=protocol,
                                jump=ipt.get_jump(target=u'ACCEPT'))
                        ]
                    ),
                    ipt.get_ring(
                        u'output',
                        transport,
                        [
                            ipt.get_rule(
                                ip_protocol_name=protocol,
                                jump=ipt.get_jump(target=u'ACCEPT'))
                        ]
                    ),
                ]
            )
        ]
    )
def create_iptables_icmp_all(slot, transport=ipt.TRANSPORT_AUTO, desc=''):
    """
    Create an rule for icmp traffic.
    :param slot: Firewall slot number
    :param transport: ipt.TRANSPORT_AUTO, ipt.TRANSPORT_IPV4 or ipt.TRANSPORT_IPV6
    :param desc: Extra description of the rule.
    :return:
    """

    if transport == ipt.TRANSPORT_AUTO:
        raise ValueError('Unable to determine transport for icmp')
    elif transport == ipt.TRANSPORT_IPV4:
        protocol = u'icmp'
    elif transport == ipt.TRANSPORT_IPV6:
        protocol = u'icmpv6'

    return ipt.get_machine_subset(
        desc,
        slot,
        [
            ipt.get_chain(
                u'filter',
                [
                    ipt.get_ring(
                        u'input',
                        transport,
                        [
                            ipt.get_rule(
                                ip_protocol_name=protocol,
                                jump=ipt.get_jump(target=u'ACCEPT'))
                        ]
                    ),
                    ipt.get_ring(
                        u'output',
                        transport,
                        [
                            ipt.get_rule(
                                ip_protocol_name=protocol,
                                jump=ipt.get_jump(target=u'ACCEPT'))
                        ]
                    ),
                ]
            )
        ]
    )
Example #8
0
def create_iptables_loopback(slot, transport=ipt.TRANSPORT_AUTO, desc=''):
    """
    Create an rule for loopback interface.
    :param slot: Firewall slot number
    :param transport: ipt.TRANSPORT_AUTO, ipt.TRANSPORT_IPV4 or ipt.TRANSPORT_IPV6
    :param desc: Extra description of the rule.
    :return:
    """

    if transport == ipt.TRANSPORT_AUTO:
        raise ValueError('Unable to determine transport for loopback')

    return ipt.get_machine_subset(
        desc,
        slot,
        [
            ipt.get_chain(
                u'filter',
                [
                    ipt.get_ring(
                        u'input',
                        transport,
                        [
                            ipt.get_rule(ifacein_name=u'lo', jump=ipt.get_jump(target=u'ACCEPT'))
                        ]
                    ),
                    ipt.get_ring(
                        u'output',
                        transport,
                        [
                            ipt.get_rule(ifaceout_name=u'lo', jump=ipt.get_jump(target=u'ACCEPT'))
                        ]
                    ),
                ]
            )
        ]
    )
def create_iptables_loopback(slot, transport=ipt.TRANSPORT_AUTO, desc=''):
    """
    Create an rule for loopback interface.
    :param slot: Firewall slot number
    :param transport: ipt.TRANSPORT_AUTO, ipt.TRANSPORT_IPV4 or ipt.TRANSPORT_IPV6
    :param desc: Extra description of the rule.
    :return:
    """

    if transport == ipt.TRANSPORT_AUTO:
        raise ValueError('Unable to determine transport for loopback')

    return ipt.get_machine_subset(
        desc,
        slot,
        [
            ipt.get_chain(
                u'filter',
                [
                    ipt.get_ring(
                        u'input',
                        transport,
                        [
                            ipt.get_rule(ifacein_name=u'lo', jump=ipt.get_jump(target=u'ACCEPT'))
                        ]
                    ),
                    ipt.get_ring(
                        u'output',
                        transport,
                        [
                            ipt.get_rule(ifaceout_name=u'lo', jump=ipt.get_jump(target=u'ACCEPT'))
                        ]
                    ),
                ]
            )
        ]
    )
Example #10
0
def create_iptables_remote_config(ipaddr, mask, port, protocol, slot, uid=None, gid=None, transport=ipt.TRANSPORT_AUTO,
                                  desc=''):
    """
    Create firewall rules for remote config.
    :param ipaddr: Destination IP address, not host name.
    :param mask: Netmask
    :param port: Destination port to use for connection
    :param protocol: protocol to use, IE: tcp, udp, icmp, ...
    :param slot: Firewall slot number
    :param transport: ipt.TRANSPORT_AUTO, ipt.TRANSPORT_IPV4 or ipt.TRANSPORT_IPV6
    :param desc: Extra description of the rule.
    :return:
    """

    rules = list()

    if ipaddr:
        # Check transport version.
        transport = check_transport_value(ipaddr, transport)
    else:
        if transport == ipt.TRANSPORT_AUTO:
            raise ValueError('Unable to determine transport from ipaddr')

    if mask:
        if transport == ipt.TRANSPORT_IPV4:
            if mask < 1 or mask > 32:
                raise ValueError('Invalid IPV4 mask value ({0}).'.format(mask))
        elif transport == ipt.TRANSPORT_IPV6:
            if mask < 1 or mask > 128:
                raise ValueError('Invalid IPV6 mask value ({0}).'.format(mask))

    if port:
        if port < 1 or port > 65536:
            raise ValueError('Invalid port value ({0}).'.format(port))

    if protocol not in [u'tcp', u'udp', u'icmp', u'udplite', u'esp', u'ah', u'sctp']:
        raise ValueError('Invalid protocol ({0}).'.format(protocol))

    dest_matches = list()
    dest_matches.append(ipt.get_match(u'state', [ipt.get_jump_option(u'--state', u'NEW,ESTABLISHED'), ], ))
    if port:
        dest_matches.append(ipt.get_match(protocol, [ipt.get_match_option(u'--dport', port), ], ))

    jump_options = list()
    if uid:
        jump_options.append(ipt.get_jump_option(u'--uid-owner', uid))

    if gid:
        jump_options.append(ipt.get_jump_option(u'--gid-owner', uid))

    if jump_options:
        dest_matches.append(ipt.get_match(u'owner', jump_options))

    if jump_options:
        rule = ipt.get_rule(ip_protocol_name=protocol, dest_address=ipaddr, dest_mask=mask, matches=dest_matches)
    else:
        rule = ipt.get_rule(ip_protocol_name=protocol, dest_address=ipaddr, dest_mask=mask, matches=dest_matches,
                            jump=ipt.get_jump(target=u'ACCEPT'))

    rules.append(
        ipt.get_machine_subset(
            desc,
            slot,
            [
                ipt.get_chain(
                    u'filter',
                    [
                        ipt.get_ring(
                            u'output',
                            transport,
                            [
                                rule
                            ]
                        ),
                    ]
                )
            ]
        )
    )

    source_matches = list()
    source_matches.append(ipt.get_match(u'state', [ipt.get_jump_option(u'--state', u'ESTABLISHED'), ], ))
    if port:
        source_matches.append(ipt.get_match(protocol, [ipt.get_match_option(u'--sport', port), ], ))

    rule = ipt.get_rule(ip_protocol_name=protocol, source_address=ipaddr, source_mask=mask, matches=source_matches,
                        jump=ipt.get_jump(target=u'ACCEPT'))

    rules.append(
        ipt.get_machine_subset(
            desc,
            slot,
            [
                ipt.get_chain(
                    u'filter',
                    [
                        ipt.get_ring(
                            u'input',
                            transport,
                            [
                                rule
                            ]
                        ),
                    ]
                )
            ]
        )
    )

    return rules
Example #11
0
def create_iptables_egress_rule_source(ipaddr, port, protocol, slot, state, transport=ipt.TRANSPORT_AUTO, desc=''):
    """
    Create an egress firewall rule for source.
    :param ipaddr: Source IP address, not host name.
    :param port: Source port to use for connection
    :param protocol: protocol to use, IE: tcp, udp, icmp, ...
    :param slot: Firewall slot number
    :param state: state of iptables: NEW,ESTABLISHED,RELATED
    :param transport: ipt.TRANSPORT_AUTO, ipt.TRANSPORT_IPV4 or ipt.TRANSPORT_IPV6
    :param desc: Extra description of the rule.
    :return:
    """

    if ipaddr:
        # Check transport version.
        transport = check_transport_value(ipaddr, transport)
    else:
        if transport == ipt.TRANSPORT_AUTO:
            raise ValueError('Unable to determine transport from ipaddr')

    if port:
        if port < 1 or port > 65536:
            raise ValueError('Invalid port value ({0}).'.format(port))

    if protocol not in [u'tcp', u'udp', u'icmp', u'udplite', u'esp', u'ah', u'sctp']:
        raise ValueError('Invalid protocol ({0}).'.format(protocol))

    if state:
        if state.strip().replace(u'NEW', '').replace(u'ESTABLISHED', '').replace(u'RELATED', '').replace(u',', ''):
            raise ValueError('Invalid Output State ({0}).'.state)
    else:
        raise ValueError('Output State is none.')

    if port:
        matches = [ipt.get_match(u'state', [ipt.get_jump_option(u'--state', state), ], ),
                   ipt.get_match(protocol, [ipt.get_match_option(u'--sport', port), ], ), ]
    else:
        matches = [ipt.get_match(u'state', [ipt.get_jump_option(u'--state', state), ], ), ]

    if ipaddr:
        rule = ipt.get_rule(ip_protocol_name=protocol, source_address=ipaddr, matches=matches,
                            jump=ipt.get_jump(target=u'ACCEPT'))
    else:
        rule = ipt.get_rule(ip_protocol_name=protocol, matches=matches, jump=ipt.get_jump(target=u'ACCEPT'))

    return ipt.get_machine_subset(
        desc,
        slot,
        [
            ipt.get_chain(
                u'filter',
                [
                    ipt.get_ring(
                        u'output',
                        transport,
                        [
                            rule
                        ]
                    ),
                ]
            )
        ]
    )
def create_iptables_remote_config(ipaddr, mask, port, protocol, slot, uid=None, gid=None, transport=ipt.TRANSPORT_AUTO,
                                  desc=''):
    """
    Create firewall rules for remote config.
    :param ipaddr: Destination IP address, not host name.
    :param mask: Netmask
    :param port: Destination port to use for connection
    :param protocol: protocol to use, IE: tcp, udp, icmp, ...
    :param slot: Firewall slot number
    :param transport: ipt.TRANSPORT_AUTO, ipt.TRANSPORT_IPV4 or ipt.TRANSPORT_IPV6
    :param desc: Extra description of the rule.
    :return:
    """

    rules = list()

    if ipaddr:
        # Check transport version.
        transport = check_transport_value(ipaddr, transport)
    else:
        if transport == ipt.TRANSPORT_AUTO:
            raise ValueError('Unable to determine transport from ipaddr')

    if mask:
        if transport == ipt.TRANSPORT_IPV4:
            if mask < 1 or mask > 32:
                raise ValueError('Invalid IPV4 mask value ({0}).'.format(mask))
        elif transport == ipt.TRANSPORT_IPV6:
            if mask < 1 or mask > 128:
                raise ValueError('Invalid IPV6 mask value ({0}).'.format(mask))

    if port:
        if port < 1 or port > 65536:
            raise ValueError('Invalid port value ({0}).'.format(port))

    if protocol not in [u'tcp', u'udp', u'icmp', u'udplite', u'esp', u'ah', u'sctp']:
        raise ValueError('Invalid protocol ({0}).'.format(protocol))

    dest_matches = list()
    dest_matches.append(ipt.get_match(u'state', [ipt.get_jump_option(u'--state', u'NEW,ESTABLISHED'), ], ))
    if port:
        dest_matches.append(ipt.get_match(protocol, [ipt.get_match_option(u'--dport', port), ], ))

    jump_options = list()
    if uid:
        jump_options.append(ipt.get_jump_option(u'--uid-owner', uid))

    if gid:
        jump_options.append(ipt.get_jump_option(u'--gid-owner', uid))

    if jump_options:
        dest_matches.append(ipt.get_match(u'owner', jump_options))

    if jump_options:
        rule = ipt.get_rule(ip_protocol_name=protocol, dest_address=ipaddr, dest_mask=mask, matches=dest_matches)
    else:
        rule = ipt.get_rule(ip_protocol_name=protocol, dest_address=ipaddr, dest_mask=mask, matches=dest_matches,
                            jump=ipt.get_jump(target=u'ACCEPT'))

    rules.append(
        ipt.get_machine_subset(
            desc,
            slot,
            [
                ipt.get_chain(
                    u'filter',
                    [
                        ipt.get_ring(
                            u'output',
                            transport,
                            [
                                rule
                            ]
                        ),
                    ]
                )
            ]
        )
    )

    source_matches = list()
    source_matches.append(ipt.get_match(u'state', [ipt.get_jump_option(u'--state', u'ESTABLISHED'), ], ))
    if port:
        source_matches.append(ipt.get_match(protocol, [ipt.get_match_option(u'--sport', port), ], ))

    rule = ipt.get_rule(ip_protocol_name=protocol, source_address=ipaddr, source_mask=mask, matches=source_matches,
                        jump=ipt.get_jump(target=u'ACCEPT'))

    rules.append(
        ipt.get_machine_subset(
            desc,
            slot,
            [
                ipt.get_chain(
                    u'filter',
                    [
                        ipt.get_ring(
                            u'input',
                            transport,
                            [
                                rule
                            ]
                        ),
                    ]
                )
            ]
        )
    )

    return rules
def create_iptables_egress_rule_source(ipaddr, port, protocol, slot, state, transport=ipt.TRANSPORT_AUTO, desc=''):
    """
    Create an egress firewall rule for source.
    :param ipaddr: Source IP address, not host name.
    :param port: Source port to use for connection
    :param protocol: protocol to use, IE: tcp, udp, icmp, ...
    :param slot: Firewall slot number
    :param state: state of iptables: NEW,ESTABLISHED,RELATED
    :param transport: ipt.TRANSPORT_AUTO, ipt.TRANSPORT_IPV4 or ipt.TRANSPORT_IPV6
    :param desc: Extra description of the rule.
    :return:
    """

    if ipaddr:
        # Check transport version.
        transport = check_transport_value(ipaddr, transport)
    else:
        if transport == ipt.TRANSPORT_AUTO:
            raise ValueError('Unable to determine transport from ipaddr')

    if port:
        if port < 1 or port > 65536:
            raise ValueError('Invalid port value ({0}).'.format(port))

    if protocol not in [u'tcp', u'udp', u'icmp', u'udplite', u'esp', u'ah', u'sctp']:
        raise ValueError('Invalid protocol ({0}).'.format(protocol))

    if state:
        if state.strip().replace(u'NEW', '').replace(u'ESTABLISHED', '').replace(u'RELATED', '').replace(u',', ''):
            raise ValueError('Invalid Output State ({0}).'.state)
    else:
        raise ValueError('Output State is none.')

    if port:
        matches = [ipt.get_match(u'state', [ipt.get_jump_option(u'--state', state), ], ),
                   ipt.get_match(protocol, [ipt.get_match_option(u'--sport', port), ], ), ]
    else:
        matches = [ipt.get_match(u'state', [ipt.get_jump_option(u'--state', state), ], ), ]

    if ipaddr:
        rule = ipt.get_rule(ip_protocol_name=protocol, source_address=ipaddr, matches=matches,
                            jump=ipt.get_jump(target=u'ACCEPT'))
    else:
        rule = ipt.get_rule(ip_protocol_name=protocol, matches=matches, jump=ipt.get_jump(target=u'ACCEPT'))

    return ipt.get_machine_subset(
        desc,
        slot,
        [
            ipt.get_chain(
                u'filter',
                [
                    ipt.get_ring(
                        u'output',
                        transport,
                        [
                            rule
                        ]
                    ),
                ]
            )
        ]
    )
Example #14
0
    def create_logging_rules(self):

        rules = list()

        rules.append(ipt.get_machine_subset(
            u'ipv4 logging rule',
            9800,
            [
                ipt.get_chain(
                    u'filter',
                    [
                        ipt.get_ring(
                            u'output',
                            ipt.TRANSPORT_IPV4,
                            [
                                ipt.get_rule(
                                    matches=[
                                        ipt.get_match('limit', options=[
                                            ipt.get_match_option('--limit', self._limit_rate),
                                        ]),
                                    ],
                                    jump=ipt.get_jump(target=u'LOG', params=[
                                        ipt.get_jump_option(u'--log-level', value="alert"),
                                        ipt.get_jump_option(u'--log-prefix', value=u'SDC: '),
                                    ])
                                )
                            ]
                        ),
                    ]
                )
            ]
        )
        )

        rules.append(ipt.get_machine_subset(
            u'ipv4 logging rule',
            9800,
            [
                ipt.get_chain(
                    u'filter',
                    [
                        ipt.get_ring(
                            u'output',
                            ipt.TRANSPORT_IPV6,
                            [
                                ipt.get_rule(
                                    matches=[
                                        ipt.get_match('limit', options=[
                                            ipt.get_match_option('--limit', self._limit_rate),
                                        ]),
                                    ],
                                    jump=ipt.get_jump(target=u'LOG', params=[
                                        ipt.get_jump_option(u'--log-level', value="alert"),
                                        ipt.get_jump_option(u'--log-prefix', value=u'SDC: '),
                                    ])
                                )
                            ]
                        ),
                    ]
                )
            ]
        )
        )

        return rules
Example #15
0
def create_tcp_server_conn_rule(addr, port, transport=ipt.TRANSPORT_AUTO, slot=120, desc=''):
    """
    Create a rule that allows access to the given addr and port.
    :param addr: IP address, not host name.
    :param port:
    :return:
    """

    # Example: a = ipt.get_match(name='state', options=[ipt.get_match_option('--state', 'ESTABLISHED')])

    if transport == ipt.TRANSPORT_AUTO:
        if is_valid_ipv6_address(addr):
            transport = ipt.TRANSPORT_IPV6
        elif is_valid_ipv4_address(addr):
            transport = ipt.TRANSPORT_IPV4
        else:
            raise ValueError
    elif transport == ipt.TRANSPORT_IPV4:
        if not is_valid_ipv4_address(addr):
            raise ValueError
    elif transport == ipt.TRANSPORT_IPV6:
        if not is_valid_ipv6_address(addr):
            raise ValueError
    else:
        raise ValueError

    return ipt.get_machine_subset(
        desc,
        slot,
        [
            ipt.get_chain(
                'filter',
                [
                    ipt.get_ring(
                        'input',
                        transport,
                        [
                            ipt.get_rule(
                                ip_protocol_name='tcp', source_address=addr, matches=[
                                    ipt.get_match('state', [ipt.get_jump_option('--state', 'ESTABLISHED'), ], ),
                                    ipt.get_match('tcp', [ipt.get_match_option('--sport', port), ], ),
                                ],
                                jump=ipt.get_jump(target='ACCEPT')
                            )]),
                    ipt.get_ring(
                        'output',
                        transport,
                        [
                            ipt.get_rule(
                                ip_protocol_name='tcp', dest_address=addr, matches=[
                                    ipt.get_match('state',
                                                  [ipt.get_jump_option('--state', 'NEW,ESTABLISHED'), ], ),
                                    ipt.get_match('tcp', [ipt.get_match_option('--dport', port), ], ),
                                ],
                                jump=ipt.get_jump(target='ACCEPT')
                            )
                        ]
                    ),
                ]
            )
        ]
    )