예제 #1
0
 def test_clear_rules(self):
     ruleset = pf.PFRuleset()
     ruleset.append(pf.PFRule(action=pf.PF_PASS,
                              flags="S", flagset="SA",
                              keep_state=pf.PF_STATE_NORMAL))
     self.pf.load_ruleset(ruleset)
     self.pf.clear_rules()
     self.assertFalse(self.pf.get_ruleset().rules)
예제 #2
0
 def _create_state(self):
     ruleset = pf.PFRuleset()
     ruleset.append(pf.PFRule(action=pf.PF_PASS,
                              flags="S", flagset="SA",
                              proto=IPPROTO_UDP,
                              keep_state=pf.PF_STATE_NORMAL))
     self.pf.load_ruleset(ruleset)
     self.pf.clear_states()
     with open(os.devnull, "w") as n:
         subprocess.call(["/usr/sbin/nslookup", "google.com"],
                         stdout=n, stderr=n)
예제 #3
0
def pfDrop(IP):
    import pf
    import socket
    filter = pf.PacketFilter()
    blockip = pf.PFAddr(IP)
    try:
        filter.enable()
        ext_if = pf.PFAddr(type=pf.PF_ADDR_DYNIFTL, ifname=options.interface)
        ruling = pf.PFRule(action=pf.PF_DROP,
                           direction=pf.PF_IN,
                           af=socket.AF_INET,
                           quick=True,
                           src=pf.PFRuleAddr(blockip))
        #rs = pf.PFRuleset()
        rs = filter.get_ruleset()
        rs.append(ruling)

        # Load rules
        #filter = pf.PacketFilter()
        filter.load_ruleset(rs)
    except:
        print "Unexpected error (pf):", sys.exc_info()[0]
        return
예제 #4
0
    def test_load_ruleset(self):
        iface = pf.PFAddr(type=pf.PF_ADDR_DYNIFTL, ifname=self.testif)
        tables = [pf.PFTable("web_srv", "10.0.1.20", "10.0.1.21", "10.0.1.22")]
        rules = [
            # match out on $ifname inet from !($ifname) to any nat-to ($ifname)
            pf.PFRule(action=pf.PF_MATCH,
                      direction=pf.PF_OUT,
                      ifname=self.testif,
                      af=AF_INET,
                      src=pf.PFRuleAddr(iface, neg=True),
                      nat=pf.PFPool(pf.PF_POOL_NAT, iface)),
            # pass out quick
            pf.PFRule(action=pf.PF_PASS,
                      direction=pf.PF_OUT,
                      quick=True,
                      flags="S", flagset="SA",
                      keep_state=pf.PF_STATE_NORMAL),
            # anchor "test_anchor"
            pf.PFRuleset("test_anchor"),
            # pass in on $ifname inet proto tcp from any to $ifname port ssh
            pf.PFRule(action=pf.PF_PASS,
                      direction=pf.PF_IN,
                      ifname=self.testif,
                      af=AF_INET,
                      proto=IPPROTO_TCP,
                      dst=pf.PFRuleAddr(iface, pf.PFPort("ssh", IPPROTO_TCP)),
                      flags="S", flagset="SA",
                      keep_state=pf.PF_STATE_NORMAL),
            # pass in on $ifname inet proto tcp to $ifname port www \
            #     rdr-to <web_srv> round-robin sticky-address
            pf.PFRule(action=pf.PF_PASS,
                      direction=pf.PF_IN,
                      ifname=self.testif,
                      af=AF_INET,
                      proto=IPPROTO_TCP,
                      dst=pf.PFRuleAddr(iface, pf.PFPort("www", IPPROTO_TCP)),
                      flags="S", flagset="SA",
                      keep_state=pf.PF_STATE_NORMAL,
                      rdr=pf.PFPool(pf.PF_POOL_RDR, pf.PFAddr("<web_srv>"),
                                    opts=(pf.PF_POOL_ROUNDROBIN|
                                          pf.PF_POOL_STICKYADDR))),
            # pass out on $ifname inet proto tcp to port 80 \
            #     divert-packet port 700
            pf.PFRule(action=pf.PF_PASS,
                      direction=pf.PF_OUT,
                      ifname=self.testif,
                      af=AF_INET,
                      proto=IPPROTO_TCP,
                      dst=pf.PFRuleAddr(port=pf.PFPort("www", IPPROTO_TCP)),
                      divert=pf.PFDivert(pf.PF_DIVERT_PACKET, port=700)),
            # pass in inet proto icmp all icmp-type echoreq max-pkt-rate 100/10
            pf.PFRule(action=pf.PF_PASS,
                      direction=pf.PF_IN,
                      af=AF_INET,
                      proto=IPPROTO_ICMP,
                      type=pf.ICMP_ECHO+1,
                      keep_state=pf.PF_STATE_NORMAL,
                      pktrate=pf.PFThreshold(100, 10))]

        rules[2].append(
            pf.PFTable("spammers", flags=pf.PFR_TFLAG_PERSIST),
            # pass in on $ifname inet proto tcp from ! <spammers> \
            #    to $ifname port 25 rdr-to 10.0.1.23
            pf.PFRule(action=pf.PF_PASS,
                      direction=pf.PF_IN,
                      ifname=self.testif,
                      af=AF_INET,
                      proto=IPPROTO_TCP,
                      src=pf.PFRuleAddr(pf.PFAddr("<spammers>"), neg=True),
                      dst=pf.PFRuleAddr(iface, pf.PFPort(25, IPPROTO_TCP)),
                      flags="S", flagset="SA",
                      keep_state=pf.PF_STATE_NORMAL,
                      rdr=pf.PFPool(pf.PF_POOL_RDR, pf.PFAddr("10.0.1.23"))))
            
        self.pf.clear_rules()
        rs = pf.PFRuleset()
        rs.append(*tables)
        rs.append(*rules)
        self.pf.load_ruleset(rs)
        self.assertEqual(len(self.pf.get_ruleset().rules), len(rules))
예제 #5
0
파일: app.py 프로젝트: nahun/pfweb
def translate_rule(pfilter, **fields):
    """Parse form fields into a pf.PFRule"""

    # Load existing or create new rule
    if fields['id'] or fields['id'] == 0:
        ruleset = pfilter.get_ruleset()
        rule = ruleset.rules[fields['id']]
    else:
        rule = pf.PFRule()

    # Set action attribute
    if fields['action'] == 'pass':
        rule.action = pf.PF_PASS
    elif fields['action'] == 'block':
        rule.action = pf.PF_DROP
        rule.rule_flag = pf.PFRULE_DROP | 0
    elif fields['action'] == 'reject':
        rule.action = pf.PF_DROP
        rule.rule_flag = pf.PFRULE_RETURN | 0
    elif fields['action'] == 'match':
        rule.action = pf.PF_MATCH
    else:
        return "Action is not recognized"

    # Set direction attribute
    if fields['direction'] == 'in':
        rule.direction = pf.PF_IN
    elif fields['direction'] == 'out':
        rule.direction = pf.PF_OUT
    elif fields['direction'] == 'both':
        rule.direction = pf.PF_INOUT
    else:
        return "Direction is not recognized"

    # Set interface attribute
    if fields['iface'] in get_ifaces(pfilter):
        rule.ifname = fields['iface']
    else:
        return "Unknown interface specified"

    # Set address family attribute
    if fields['af'] == '*':
        rule.af = socket.AF_UNSPEC
    elif fields['af'] == 'IPv4':
        rule.af = socket.AF_INET
    elif fields['af'] == 'IPv6':
        rule.af = socket.AF_INET6
    else:
        return "Unknown address family type"

    # Set protocol attribute
    if fields['proto'] == '*':
        rule.proto = socket.IPPROTO_IP
    elif fields['proto'] == 'TCP':
        rule.proto = socket.IPPROTO_TCP
    elif fields['proto'] == 'UDP':
        rule.proto = socket.IPPROTO_UDP
    elif fields['proto'] == 'ICMP' and fields['af'] == 'IPv4':
        rule.proto = socket.IPPROTO_ICMP
    elif fields['proto'] == 'ICMP' and fields['af'] == 'IPv6':
        rule.proto = socket.IPPROTO_ICMPV6
    else:
        return "Protocol is not supported"

    # ICMP Type
    if fields['proto'] == "ICMP":
        # Use ICMP or ICMP6 depending on AF
        if rule.af == socket.AF_INET:
            if fields['icmptype'] == 'any':
                rule.type = 0
            elif int(fields['icmptype']) in PFWEB_ICMP_TYPES:
                rule.type = int(fields['icmptype']) + 1
            else:
                return "Invalid ICMP Type"
        elif rule.af == socket.AF_INET6:
            if fields['icmp6type'] == 'any':
                rule.type = 0
            elif int(fields['icmp6type']) in PFWEB_ICMP6_TYPES:
                rule.type = int(fields['icmp6type']) + 1
            else:
                return "Invalid ICMP Type"
        else:
            return "Must specifiy IPv4 or IPv6 when using ICMP"

    # Source Address Rule
    rule.src = translate_addr_rule(fields.get('src_addr'),
                                   fields.get('src_addr_type'),
                                   fields.get('src_addr_table'),
                                   fields.get('src_port_op', pf.PF_OP_NONE),
                                   fields.get('src_port_from', 0),
                                   fields.get('src_port_to', 0), rule.proto,
                                   fields.get('src_addr_iface'), rule.af)
    # Destination Address Rule
    rule.dst = translate_addr_rule(fields.get('dst_addr'),
                                   fields.get('dst_addr_type'),
                                   fields.get('dst_addr_table'),
                                   fields.get('dst_port_op', pf.PF_OP_NONE),
                                   fields.get('dst_port_from', 0),
                                   fields.get('dst_port_to', 0), rule.proto,
                                   fields.get('dst_addr_iface'), rule.af)

    # Set any translation used NAT or RDR
    if fields.get('trans_type', 'none') != 'none' and (
            rule.af == socket.AF_INET or rule.af == socket.AF_INET6):
        pool = translate_pool_rule(fields.get('trans_type'),
                                   fields.get('trans_addr'),
                                   fields.get('trans_addr_type'),
                                   fields.get('trans_addr_table'),
                                   fields.get('trans_port_from'),
                                   fields.get('trans_port_to'), rule.proto,
                                   fields.get('trans_addr_iface'), rule.af)

        if fields['trans_type'].lower() == 'rdr':
            rule.rdr = pool
            rule.nat.addr.type = pf.PF_ADDR_NONE
        else:
            # Enable static port option
            if 'nat_static_port' in fields:
                pool.proxy_port = pf.PFPort((0, 0))
            rule.nat = pool
            rule.rdr.addr.type = pf.PF_ADDR_NONE
    elif fields.get('trans_type', 'none') != 'none':
        return "Must specify IPv4 or IPv6 with translation"
    else:
        # Translation is disabled
        rule.rdr.addr.type = pf.PF_ADDR_NONE
        rule.nat.addr.type = pf.PF_ADDR_NONE

    # Log checkbox
    if 'log' in fields:
        rule.log = pf.PF_LOG
    else:
        rule.log = 0

    # Quick checkbox
    if 'quick' in fields:
        rule.quick = True
    else:
        rule.quick = False

    # Keep state checkbox
    if 'keep_state' in fields:
        rule.keep_state = pf.PF_STATE_NORMAL
    else:
        rule.keep_state = 0

    if 'label' in fields:
        rule.label = fields['label']

    return rule
예제 #6
0
파일: app.py 프로젝트: nahun/pfweb
def edit_rule(rule_id=None):
    """Edit a single rule"""

    # Save edit or new rule
    if request.method == 'POST':
        # Get all form items into simple dict
        fields = dict()
        for item, val in request.form.iteritems():
            fields[item] = val

        # Parse user input into pf.PFRule object
        rule = translate_rule(packetfilter, id=rule_id, **fields)

        if not isinstance(rule, pf.PFRule):
            raise BadRequestError(rule)

        ruleset = packetfilter.get_ruleset()
        message = None
        if rule_id or rule_id == 0:
            ruleset.remove(rule_id)
            ruleset.insert(rule_id, rule)
            message = PFWEB_ALERT_SUCCESS_EDIT
        else:
            ruleset.append(rule)
            message = PFWEB_ALERT_SUCCESS_ADD

        packetfilter.load_ruleset(ruleset)
        save_pfconf(packetfilter)

        # redirect to rules page
        return redirect(url_for('rules', message=message), code=302)

    # Load existing or create new rule
    if rule_id or rule_id == 0:
        # Load the current ruleset and parse existing rule
        ruleset = packetfilter.get_ruleset()
        rule = get_rule(ruleset.rules[rule_id])
        # Set the ID
        rule['id'] = rule_id
    else:
        # Create new blank rule
        blank_rule = pf.PFRule()
        # Direction is in by default
        blank_rule.direction = pf.PF_IN
        # Use IPv4 by default
        blank_rule.af = socket.AF_INET
        # Enable keep_state by default
        blank_rule.keep_state = pf.PF_STATE_NORMAL
        rule = get_rule(blank_rule)

    tables = get_tables(packetfilter)

    return render_template('edit_rule.html',
                           logged_in=flask_login.current_user.get_id(),
                           fw_tab='active',
                           rule=rule,
                           tables=tables,
                           ifaces=get_ifaces(packetfilter),
                           icmp_types=PFWEB_ICMP_TYPES,
                           icmp6_types=PFWEB_ICMP6_TYPES,
                           port_ops=PFWEB_PORT_OPS)
예제 #7
0
def xml_to_pfrule(data):
    print "starting translation"
    print data
    xml_datas = []
    xml_rules = xmltodict.parse(
        data,
        dict_constructor=dict
    )["mspl-set"]["it-resource"]["configuration"]["rule"]
    if isinstance(xml_rules, list):
        for xml_rule in xml_rules:
            xml_datas.append(xml_rule)
    else:
        xml_datas.append(xml_rules)
    rate_limit = None
    rules = pf.PFRuleset()
    for xml_data in xml_datas:
        print xml_data
        rule = pf.PFRule()
        if settings.quick_rules == "True":
            rule.quick = True
        Addrs = None
        Addrd = None
        Ports = None
        Portd = None
        xml_src = getValIfKeyExists(
            xml_data["condition"]["packet-filter-condition"], "source-address")
        if xml_src is not None:
            Addrs = pf.PFAddr(xml_src)
        xml_dst = getValIfKeyExists(
            xml_data["condition"]["packet-filter-condition"],
            "destination-address")
        if xml_dst is not None:
            Addrd = pf.PFAddr(xml_dst)
        xml_proto = getValIfKeyExists(
            xml_data["condition"]["packet-filter-condition"],
            "protocol")
        if xml_proto is not None:
            if xml_proto.lower() == "tcp":
                rule.proto = socket.IPPROTO_TCP
            elif xml_proto.lower() == "udp":
                rule.proto = socket.IPPROTO_UDP
        xml_direction = getValIfKeyExists(
            xml_data["condition"]["packet-filter-condition"],
            "direction")
        if xml_direction is not None:
            if xml_direction.lower() == "inbound":
                rule.direction = pf.PF_IN
            elif xml_direction.lower() == "outbound":
                rule.direction = pf.PF_OUT
        xml_interface = getValIfKeyExists(
            xml_data["condition"]["packet-filter-condition"],
            "interface")
        if xml_interface is not None:
            rule.ifname = xml_interface.replace("eth", "vtnet")
        xml_sport = getValIfKeyExists(
            xml_data["condition"]["packet-filter-condition"], "source-port")
        xml_dport = getValIfKeyExists(
            xml_data["condition"]["packet-filter-condition"],
            "destination-port")
        # Retrieve default target from MSPL
        default_target = getValIfKeyExists(xml_data, "action").upper()
        if default_target is not None:
            if default_target == "ACCEPT":
                rule.action = pf.PF_PASS
                rule.keep_state = pf.PF_STATE_NORMAL
            elif default_target == "DROP":
                rule.action = pf.PF_DROP
            elif default_target == "REJECT":
                rule.action = pf.PF_DROP
                rule.rule_flag = pf.PFRULE_RETURN
            elif default_target == "SCRUB":
                rule.action = pf.PF_SCRUB
        # In case of packets/sec rate limit:
        if getValIfKeyExists(
                xml_data["condition"],
                "traffic-flow-condition") is not None:
            # It is a number of allowed packets or bits per unit of time
            # (seconds, minutes, hours or days).
            # -m limit --limit <rate-limit> --limit-burst <limit-burst> \
            # -j ACCEPT
            # rate_limit = getValIfKeyExists(
            #    xml_data["condition"]["traffic-flow-condition"],
            #    "rate-limit")

            # The maximum number of connections per host.
            max_connections = getValIfKeyExists(
                xml_data["condition"]["traffic-flow-condition"],
                "max-connections")
            # If the action is DROP or REJECT the rule will fire an error
            # if max_src_conn is setted
            if max_connections is not None and default_target == "ACCEPT":
                # rule.max_src_nodes = max_connections
                rule.max_src_conn = max_connections
                rule.rule_flag = pf.PFRULE_SRCTRACK
            # Connections rate limit
            connections_rate = getValIfKeyExists(
                xml_data["condition"]["traffic-flow-condition"],
                "connections-rate")
            # If the action is DROP or REJECT the rule will fire an error
            # if max_src_conn_rate is setted
            if connections_rate is not None and default_target == "ACCEPT":
                splitted = connections_rate.split('/')
                # rule.max_src_nodes = max_connections
                limit = splitted[0]
                seconds = splitted[1]
                rule.max_src_conn_rate = (limit, seconds)
                rule.rule_flag = pf.PFRULE_SRCTRACK
        # In case of specified ports, ports can be applied only
        # if protocol is specified:
        if xml_sport is not None:
            if xml_proto is not None:
                if xml_proto.lower() == "tcp":
                    Ports = pf.PFPort(xml_sport, socket.IPPROTO_TCP)
                elif xml_proto.lower() == "udp":
                    Ports = pf.PFPort(xml_sport, socket.IPPROTO_UDP)
            else:
                Ports = pf.PFPort(xml_sport)
        if xml_dport is not None:
            if xml_proto is not None:
                if xml_proto.lower() == "tcp":
                    Portd = pf.PFPort(xml_dport, socket.IPPROTO_TCP)
                elif xml_proto.lower() == "udp":
                    Portd = pf.PFPort(xml_dport, socket.IPPROTO_UDP)
            else:
                print xml_dport
                Portd = pf.PFPort(xml_dport)
        # TODO: Manage Priority
        priority = getValIfKeyExists(xml_data, "priority")
        if Addrs is not None and Ports is not None:
            rule.src = pf.PFRuleAddr(Addrs, Ports)
        elif Addrs is not None:
            rule.src = pf.PFRuleAddr(Addrs)
        elif Ports is not None:
            rule.src = pf.PFRuleAddr(pf.PFAddr(), Ports)
        if Addrd is not None and Portd is not None:
            rule.dst = pf.PFRuleAddr(Addrd, Portd)
        elif Addrd is not None:
            rule.dst = pf.PFRuleAddr(Addrd)
        elif Portd is not None:
            rule.dst = pf.PFRuleAddr(pf.PFAddr(), Portd)
        # Append rule
        rules.append(rule)
    return rules