def interface_condition_string_to_interface_list( value ): intfs = [] for substr in value.split(","): if substr == "wan": intf_values = NetworkUtil.wan_list() for intfId in intf_values: if intfId not in intfs: intfs.append(intfId) elif substr == "non_wan": intf_values = NetworkUtil.non_wan_list() for intfId in intf_values: if intfId not in intfs: intfs.append(intfId) else: intfs.append(int(substr)) return intfs
def interface_condition_string_to_interface_list(value): intfs = [] for substr in value.split(","): if substr == "wan": intf_values = NetworkUtil.wan_list() for intfId in intf_values: if intfId not in intfs: intfs.append(intfId) elif substr == "non_wan": intf_values = NetworkUtil.non_wan_list() for intfId in intf_values: if intfId not in intfs: intfs.append(intfId) else: intfs.append(int(substr)) return intfs
def write_bypass_rules(self, settings, verbosity=0): if settings == None or 'bypassRules' not in settings or 'list' not in settings[ 'bypassRules']: print("ERROR: Missing Bypass Rules") return bypass_rules = settings['bypassRules']['list'] self.file.write("# Implicit Bypass Rules (loopback)" + "\n") self.file.write( "${IPTABLES} -t filter -A bypass-rules -i lo --goto set-bypass-mark -m comment --comment \"Bypass loopback traffic\"" + "\n") self.file.write( "${IPTABLES} -t filter -A bypass-rules -o lo --goto set-bypass-mark -m comment --comment \"Bypass loopback traffic\"" + "\n") self.file.write("\n") # If its RELATED, it must be RELATED to an already bypassed session, so bypass it also self.file.write("# Implicit Bypass Rules (RELATED)" + "\n") self.file.write( "${IPTABLES} -t filter -A bypass-rules -m conntrack --ctstate RELATED --goto set-bypass-mark -m comment --comment \"Bypass RELATED sessions\"" + "\n") self.file.write("\n") # We bypass DHCP reply traffic, because the host doesn't technically have an address yet, so our destination interface lookup will fail. # This assures its just sent across the bridge in normal fashion self.file.write("# Implicit Bypass Rules (DHCP)" + "\n") self.file.write( "${IPTABLES} -t filter -A bypass-rules -p udp --source-port 67:68 --destination-port 67:68 --goto set-bypass-mark -m comment --comment \"Bypass DHCP traffic\"" + "\n") self.file.write("\n") # We bypass routing protocols # http://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml self.file.write("# Implicit Bypass Rules (multicast)" + "\n") self.file.write( "${IPTABLES} -t filter -A bypass-rules --destination 224.0.0.0/4 --goto set-bypass-mark -m comment --comment \"Bypass 224 traffic\"" + "\n") self.file.write("\n") # We bypass 'hairpin' traffic because end-pointing it at layer 7 wouldn't work because two sessions would have identical tuples self.file.write("# Implicit Bypass Rules (hairpin)" + "\n") for intfId in NetworkUtil.interface_list(): self.file.write( "${IPTABLES} -t filter -A bypass-rules -m mark --mark 0x%X/0x%X --goto set-bypass-mark -m comment --comment \"Bypass hairpin traffic (interface %s)\"" % ((intfId + (intfId << 8)), self.interfaces_mark_mask, str(intfId)) + "\n") self.file.write("\n") # Add the user bypass rules for bypass_rule in bypass_rules: try: self.write_bypass_rule(bypass_rule, verbosity) except Exception as e: traceback.print_exc()
def write_implicit_nat_rules(self, settings): self.file.write("# Implicit NAT Rule (hairpin for port forwards)" + "\n") for intfId in NetworkUtil.interface_list(): self.file.write( "${IPTABLES} -t nat -A nat-rules -m conntrack --ctstate DNAT -m connmark --mark 0x%X/0x%X -j MASQUERADE -m comment --comment \"NAT all port forwards (hairpin) (interface %s)\"" % ((intfId + (intfId << 8)), self.interfaces_mark_mask, str(intfId)) + "\n") self.file.write("\n")
def write_wireguard_iptables_rules(iptables_table_chain_rules, wireguard_ip_address=''): """ Write iptables specific rules for wireguard """ delete_rule_template = "$IPTABLES -t {table} -D {chain} {rule} >/dev/null 2>&1" wan_marks = [] for interface_id in NetworkUtil.wan_list(): wan_marks.append(hex((interface_id << 8) + 0x00f9)) delete_rules = [] new_rules = [] iptables_table_format_map = IptablesUtil.iptables_wireguard_table_format_map iptables_table_format_map[ 'wireguard_ip_address'] = wireguard_ip_address for table in sorted(iptables_table_chain_rules.keys()): for chain in sorted(iptables_table_chain_rules[table].keys()): format_map = {'table': table, 'chain': chain} for rule in iptables_table_chain_rules[table][chain]: updated_rule = rule['rule'].format_map( iptables_table_format_map) format_map['comment'] = None if 'comment' in rule: format_map['comment'] = rule['comment'] else: iptables_rule_comment_re = re.compile( r'--comment "([^"]+)"') match = re.search(iptables_rule_comment_re, rule['rule']) if match: format_map['comment'] = match.group(1) if format_map['comment'] is not None: delete_rules.append( '## {comment}'.format_map(format_map)) new_rules.append('## {comment}'.format_map(format_map)) if '{wan_mark}' in updated_rule: for wan_mark in wan_marks: format_map['rule'] = updated_rule.format( wan_mark=wan_mark) delete_rules.append( delete_rule_template.format_map(format_map)) new_rules.append( IptablesUtil.create_new_rule(rule, format_map)) else: format_map['rule'] = updated_rule delete_rules.append( delete_rule_template.format_map(format_map)) new_rules.append( IptablesUtil.create_new_rule(rule, format_map)) delete_rules.append("") new_rules.append("") return delete_rules, new_rules
def interface_condition_string_to_interface_list(value): """ Real, actual interface ids (integers) from settings """ intfs = [] for substr in value.split(","): if substr == "wan": intf_values = NetworkUtil.wan_list() for intfId in intf_values: if intfId not in intfs: intfs.append(intfId) elif substr == "non_wan": intf_values = NetworkUtil.non_wan_list() for intfId in intf_values: if intfId not in intfs: intfs.append(intfId) elif substr.isnumeric(): intfs.append(int(substr)) return intfs
def write_bypass_rules(self, settings): if settings == None or 'bypassRules' not in settings: print("ERROR: Missing Bypass Rules") return bypass_rules = settings['bypassRules'] self.file.write("# Implicit Bypass Rules (loopback)" + "\n") self.file.write("${IPTABLES} -t filter -A bypass-rules -i lo --goto set-bypass-mark -m comment --comment \"Bypass loopback traffic\"" + "\n") self.file.write("${IPTABLES} -t filter -A bypass-rules -o lo --goto set-bypass-mark -m comment --comment \"Bypass loopback traffic\"" + "\n") self.file.write("\n") # If its RELATED, it must be RELATED to an already bypassed session, so bypass it also self.file.write("# Implicit Bypass Rules (RELATED)" + "\n") self.file.write("${IPTABLES} -t filter -A bypass-rules -m conntrack --ctstate RELATED --goto set-bypass-mark -m comment --comment \"Bypass RELATED sessions\"" + "\n") self.file.write("\n") # We bypass DHCP reply traffic, because the host doesn't technically have an address yet, so our destination interface lookup will fail. # This assures its just sent across the bridge in normal fashion self.file.write("# Implicit Bypass Rules (DHCP)" + "\n") self.file.write("${IPTABLES} -t filter -A bypass-rules -p udp --source-port 67:68 --destination-port 67:68 --goto set-bypass-mark -m comment --comment \"Bypass DHCP traffic\"" + "\n") self.file.write("\n") # We bypass routing protocols # http://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml self.file.write("# Implicit Bypass Rules (multicast)" + "\n") self.file.write("${IPTABLES} -t filter -A bypass-rules --destination 224.0.0.0/4 --goto set-bypass-mark -m comment --comment \"Bypass 224 traffic\"" + "\n") self.file.write("\n") # We bypass 'hairpin' traffic because end-pointing it at layer 7 wouldn't work because two sessions would have identical tuples self.file.write("# Implicit Bypass Rules (hairpin)" + "\n") for intfId in NetworkUtil.interface_list(): self.file.write("${IPTABLES} -t filter -A bypass-rules -m mark --mark 0x%X/0x%X --goto set-bypass-mark -m comment --comment \"Bypass hairpin traffic (interface %s)\"" % ((intfId+(intfId << 8)), self.interfaces_mark_mask, str(intfId)) + "\n") self.file.write("\n") # Add the user bypass rules for bypass_rule in bypass_rules: try: self.write_bypass_rule(bypass_rule) except Exception as e: traceback.print_exc()
def write_routes(self, settings, prefix): filename = prefix + self.routes_filename file_dir = os.path.dirname(filename) if not os.path.exists(file_dir): os.makedirs(file_dir) file = open(filename, "w+") file.write("#!/bin/dash") file.write("\n\n") file.write("## Auto Generated\n") file.write("## DO NOT EDIT. Changes will be overwritten.\n") file.write("\n\n") file.write("expected_ip_route_rules()" + "\n") file.write("{" + "\n") for intfId in NetworkUtil.wan_list(): file.write( " printf \"%s%03d:\\tfrom all fwmark %#x/%#x lookup uplink.%d \\n\"\n" % (self.IP_RULE_PRIORITY, intfId, intfId << self.DST_INTERFACE_SHIFT, self.DST_INTERFACE_MASK, intfId)) file.write("}" + "\n") file.write("\n\n") file.write(r""" current_ip_route_rules() { ip rule show | awk "/^%s[0-9][0-9][0-9]:/ { print }" } """ % self.IP_RULE_PRIORITY) file.write("\n\n") file.write(r""" flush_ip_route_rules() { local t_priority for t_priority in `ip rule show | awk "/^%s[0-9][0-9][0-9]:/ { sub( \":\", \"\", \\$1 ) ; print \\$1 }"`; do ip rule del priority ${t_priority} done } """ % self.IP_RULE_PRIORITY) file.write("\n\n") file.write("insert_ip_route_rules()" + "\n") file.write("{" + "\n") for intfId in NetworkUtil.wan_list(): file.write( " ip rule add priority %s%03d fwmark %#x/%#x lookup uplink.%i\n" % (self.IP_RULE_PRIORITY, intfId, intfId << self.DST_INTERFACE_SHIFT, self.DST_INTERFACE_MASK, intfId)) file.write("}" + "\n") file.write(r""" if [ "`expected_ip_route_rules | md5sum`" != "`current_ip_route_rules | md5sum`" ]; then echo "Flushing ip route rules..." flush_ip_route_rules echo "Inserting ip route rules..." insert_ip_route_rules fi """) # Write the static routes from settings if settings == None or 'staticRoutes' not in settings: print("ERROR: Missing Static Routes") else: static_routes = settings['staticRoutes'] for static_route in static_routes: for key in ['ruleId', 'nextHop', 'network', 'prefix']: if key not in static_route: print("ERROR: ignoring bad route missing key: %s\n" % key) continue if self.string_is_int(static_route['nextHop']): # if nextHop is an interfaceId interfaceId = int(static_route['nextHop']) for intf in settings['interfaces']: if intf.get('interfaceId') == interfaceId: # device route since nextHop includes alphas file.write("# Static Route %i\n" % static_route['ruleId']) file.write("ip route add %s/%s dev %s\n" % (static_route['network'], static_route['prefix'], intf.get('symbolicDev'))) file.write( "if [ $? != 0 ] ; then echo \"ERROR: inserting route %i\" ; fi \n" % static_route['ruleId']) file.write("\n") else: # otherwise gateway route file.write("# Static Route %i\n" % static_route['ruleId']) file.write( "ip route add %s/%s via %s\n" % (static_route['network'], static_route['prefix'], static_route['nextHop'])) file.write( "if [ $? != 0 ] ; then echo \"ERROR: inserting route %i\" ; fi \n" % static_route['ruleId']) file.write("\n") file.flush() file.close() os.chmod(filename, os.stat(filename).st_mode | stat.S_IEXEC) print("RouteManager: Wrote %s" % filename) return
def write_filter_rules_file(self, settings, prefix=""): self.filename = prefix + self.iptables_filename self.file_dir = os.path.dirname(self.filename) if not os.path.exists(self.file_dir): os.makedirs(self.file_dir) self.file = open(self.filename, "w+") self.file.write("## Auto Generated\n") self.file.write("## DO NOT EDIT. Changes will be overwritten.\n") self.file.write("\n") self.file.write("\n") self.file.write("# Create (if needed) and flush access-rules chain" + "\n") self.file.write("${IPTABLES} -t filter -N access-rules 2>/dev/null" + "\n") self.file.write("${IPTABLES} -t filter -F access-rules >/dev/null 2>&1" + "\n") self.file.write("\n") self.file.write("${IP6TABLES} -t filter -N access-rules 2>/dev/null" + "\n") self.file.write("${IP6TABLES} -t filter -F access-rules >/dev/null 2>&1" + "\n") self.file.write("\n") self.file.write("# Create (if needed) and flush access-rules chain" + "\n") self.file.write("${IPTABLES} -t filter -N filter-rules 2>/dev/null" + "\n") self.file.write("${IPTABLES} -t filter -F filter-rules >/dev/null 2>&1" + "\n") self.file.write("\n") self.file.write("${IP6TABLES} -t filter -N filter-rules 2>/dev/null" + "\n") self.file.write("${IP6TABLES} -t filter -F filter-rules >/dev/null 2>&1" + "\n") self.file.write("\n") self.file.write("# Create (if needed) and flush access-rules chain" + "\n") self.file.write("${IPTABLES} -t filter -N block-invalid 2>/dev/null" + "\n") self.file.write("${IPTABLES} -t filter -F block-invalid >/dev/null 2>&1" + "\n") self.file.write("\n") self.file.write("${IP6TABLES} -t filter -N block-invalid 2>/dev/null" + "\n") self.file.write("${IP6TABLES} -t filter -F block-invalid >/dev/null 2>&1" + "\n") self.file.write("\n") self.file.write("# Call access-rules chain from INPUT/filter chain" + "\n") self.file.write("${IPTABLES} -t filter -D INPUT -m conntrack --ctstate NEW -m comment --comment \"input filter rules\" -j access-rules >/dev/null 2>&1" + "\n") self.file.write("${IPTABLES} -t filter -A INPUT -m conntrack --ctstate NEW -m comment --comment \"input filter rules\" -j access-rules" + "\n") self.file.write("\n") self.file.write("${IP6TABLES} -t filter -D INPUT -m conntrack --ctstate NEW -m comment --comment \"input filter rules\" -j access-rules >/dev/null 2>&1" + "\n") self.file.write("${IP6TABLES} -t filter -A INPUT -m conntrack --ctstate NEW -m comment --comment \"input filter rules\" -j access-rules" + "\n") self.file.write("\n") self.file.write("# Call filter-rules chain from FORWARD/filter chain" + "\n") self.file.write("${IPTABLES} -t filter -D FORWARD -m conntrack --ctstate NEW -m comment --comment \"forward filter rules\" -j filter-rules >/dev/null 2>&1" + "\n") self.file.write("${IPTABLES} -t filter -A FORWARD -m conntrack --ctstate NEW -m comment --comment \"forward filter rules\" -j filter-rules" + "\n") self.file.write("\n") self.file.write("${IP6TABLES} -t filter -D FORWARD -m conntrack --ctstate NEW -m comment --comment \"forward filter rules\" -j filter-rules >/dev/null 2>&1" + "\n") self.file.write("${IP6TABLES} -t filter -A FORWARD -m conntrack --ctstate NEW -m comment --comment \"forward filter rules\" -j filter-rules" + "\n") self.file.write("\n") self.file.write("# Pass all local traffic " + "\n") self.file.write("${IPTABLES} -t filter -D access-rules -i lo -j RETURN -m comment --comment \"Allow all local traffic\" >/dev/null 2>&1" + "\n") self.file.write("${IPTABLES} -t filter -I access-rules -i lo -j RETURN -m comment --comment \"Allow all local traffic\"" + "\n") self.file.write("\n") self.file.write("${IP6TABLES} -t filter -D access-rules -i lo -j RETURN -m comment --comment \"Allow all local traffic\" >/dev/null 2>&1" + "\n") self.file.write("${IP6TABLES} -t filter -I access-rules -i lo -j RETURN -m comment --comment \"Allow all local traffic\"" + "\n") self.file.write("\n") self.file.write("# Block INVALID packets" + "\n") self.file.write("${IPTABLES} -t filter -D block-invalid -m conntrack --ctstate INVALID -j DROP -m comment --comment \"Block INVALID packets\" >/dev/null 2>&1" + "\n") self.file.write("${IPTABLES} -t filter -I block-invalid -m conntrack --ctstate INVALID -j DROP -m comment --comment \"Block INVALID packets\" " + "\n") self.file.write("${IPTABLES} -t filter -D block-invalid -m conntrack --ctstate INVALID -j NFLOG --nflog-prefix \"invalid_blocked\" -m comment --comment \"nflog on invalid\" >/dev/null 2>&1\n") self.file.write("${IPTABLES} -t filter -I block-invalid -m conntrack --ctstate INVALID -j NFLOG --nflog-prefix \"invalid_blocked\" -m comment --comment \"nflog on invalid\"\n") for intfId in NetworkUtil.interface_list(): self.file.write("${IPTABLES} -t filter -I block-invalid -m mark --mark 0x%X/0x%X -j RETURN -m comment --comment \"Allow INVALID hairpin traffic (interface %s)\"" % ((intfId+(intfId << 8)), self.interfaces_mark_mask, str(intfId)) + "\n") self.file.write("${IPTABLES} -t filter -I block-invalid -m mark --mark 0xfe00/0xff00 -j RETURN -m comment --comment \"Allow INVALID to local sockets (interface 0xfe)\"" + "\n") self.file.write("\n") self.file.write("# Block INVALID packets" + "\n") self.file.write("${IP6TABLES} -t filter -D block-invalid -m conntrack --ctstate INVALID -j DROP -m comment --comment \"Block INVALID packets\" >/dev/null 2>&1" + "\n") self.file.write("${IP6TABLES} -t filter -I block-invalid -m conntrack --ctstate INVALID -j DROP -m comment --comment \"Block INVALID packets\" " + "\n") # disabled because I don't think the nflog daemon handles IPv6 currently #self.file.write("${IP6TABLES} -t filter -D block-invalid -m conntrack --ctstate INVALID -j NFLOG --nflog-prefix \"invalid_blocked\" -m comment --comment \"nflog on invalid\" >/dev/null 2>&1\n"); #self.file.write("${IP6TABLES} -t filter -I block-invalid -m conntrack --ctstate INVALID -j NFLOG --nflog-prefix \"invalid_blocked\" -m comment --comment \"nflog on invalid\"\n"); for intfId in NetworkUtil.interface_list(): self.file.write("${IP6TABLES} -t filter -I block-invalid -m mark --mark 0x%X/0x%X -j RETURN -m comment --comment \"Allow INVALID hairpin traffic (interface %s)\"" % ((intfId+(intfId << 8)), self.interfaces_mark_mask, str(intfId)) + "\n") self.file.write("${IP6TABLES} -t filter -I block-invalid -m mark --mark 0xfe00/0xff00 -j RETURN -m comment --comment \"Allow INVALID to local sockets (interface 0xfe)\"" + "\n") self.file.write("\n") if settings.get('blockInvalidPackets'): self.file.write("# Block INVALID packets" + "\n") self.file.write("${IPTABLES} -t filter -D INPUT -m conntrack --ctstate INVALID -j block-invalid -m comment --comment \"Block INVALID\" >/dev/null 2>&1" + "\n") self.file.write("${IPTABLES} -t filter -A INPUT -m conntrack --ctstate INVALID -j block-invalid -m comment --comment \"Block INVALID\"" + "\n") self.file.write("\n") self.file.write("# Block INVALID packets" + "\n") self.file.write("${IPTABLES} -t filter -D FORWARD -m conntrack --ctstate INVALID -j block-invalid -m comment --comment \"Block INVALID\" >/dev/null 2>&1" + "\n") self.file.write("${IPTABLES} -t filter -A FORWARD -m conntrack --ctstate INVALID -j block-invalid -m comment --comment \"Block INVALID\"" + "\n") self.file.write("\n") self.file.write("# Pass all RELATED traffic " + "\n") self.file.write("${IPTABLES} -t filter -D access-rules -m conntrack --ctstate RELATED -j RETURN -m comment --comment \"Allow RELATED traffic\" >/dev/null 2>&1" + "\n") self.file.write("${IPTABLES} -t filter -I access-rules -m conntrack --ctstate RELATED -j RETURN -m comment --comment \"Allow RELATED traffic\"" + "\n") self.file.write("\n") self.file.write("${IP6TABLES} -t filter -D access-rules -m conntrack --ctstate RELATED -j RETURN -m comment --comment \"Allow RELATED traffic\" >/dev/null 2>&1" + "\n") self.file.write("${IP6TABLES} -t filter -I access-rules -m conntrack --ctstate RELATED -j RETURN -m comment --comment \"Allow RELATED traffic\"" + "\n") self.file.write("\n") self.file.write("# Pass all RELATED traffic " + "\n") self.file.write("${IPTABLES} -t filter -D filter-rules -m conntrack --ctstate RELATED -j RETURN -m comment --comment \"Allow RELATED traffic\" >/dev/null 2>&1" + "\n") self.file.write("${IPTABLES} -t filter -I filter-rules -m conntrack --ctstate RELATED -j RETURN -m comment --comment \"Allow RELATED traffic\"" + "\n") self.file.write("\n") self.file.write("${IP6TABLES} -t filter -D filter-rules -m conntrack --ctstate RELATED -j RETURN -m comment --comment \"Allow RELATED traffic\" >/dev/null 2>&1" + "\n") self.file.write("${IP6TABLES} -t filter -I filter-rules -m conntrack --ctstate RELATED -j RETURN -m comment --comment \"Allow RELATED traffic\"" + "\n") self.file.write("\n") # This is commented out because we have explicit rules to handle admin & blockpages in the input rules. # self.file.write("# Pass all port forwarded traffic (for block pages & admin) " + "\n"); # self.file.write("${IPTABLES} -t filter -D access-rules -m conntrack --ctstate DNAT -j RETURN -m comment --comment \"Allow port forwarded traffic\" >/dev/null 2>&1" + "\n"); # self.file.write("${IPTABLES} -t filter -I access-rules -m conntrack --ctstate DNAT -j RETURN -m comment --comment \"Allow port forwarded traffic\"" + "\n"); # self.file.write("\n"); self.file.write("# Pass all reinjected TCP traffic " + "\n") self.file.write("${IPTABLES} -t filter -D access-rules -i utun -j RETURN -m comment --comment \"Allow all reinjected traffic\" >/dev/null 2>&1" + "\n") self.file.write("${IPTABLES} -t filter -I access-rules -i utun -j RETURN -m comment --comment \"Allow all reinjected traffic\"" + "\n") self.file.write("\n") self.file.write("${IP6TABLES} -t filter -D access-rules -i utun -j RETURN -m comment --comment \"Allow all reinjected traffic\" >/dev/null 2>&1" + "\n") self.file.write("${IP6TABLES} -t filter -I access-rules -i utun -j RETURN -m comment --comment \"Allow all reinjected traffic\"" + "\n") self.file.write("\n") if settings.get('blockReplayPackets'): self.file.write("# Block Replay packets" + "\n") # more info in bug #12357 #12358 #12359 self.file.write("${IPTABLES} -t filter -D FORWARD -p tcp --tcp-flags RST RST -j CONNMARK --set-mark 0x02000000/0x02000000 -m comment --comment \"set replay bit\" >/dev/null 2>&1" + "\n") self.file.write("${IPTABLES} -t filter -I FORWARD -p tcp --tcp-flags RST RST -j CONNMARK --set-mark 0x02000000/0x02000000 -m comment --comment \"set replay bit\" " + "\n") self.file.write("${IPTABLES} -t filter -D FORWARD -p tcp --tcp-flags RST RST -m connmark --mark 0x02000000/0x02000000 -m state --state RELATED -j DROP -m comment --comment \"drop if replay\" >/dev/null 2>&1" + "\n") self.file.write("${IPTABLES} -t filter -I FORWARD -p tcp --tcp-flags RST RST -m connmark --mark 0x02000000/0x02000000 -m state --state RELATED -j DROP -m comment --comment \"drop if replay\" " + "\n") self.file.write("${IPTABLES} -t filter -D FORWARD -p icmp ! --icmp-type 8 -m state --state RELATED -j CONNMARK --set-mark 0x02000000/0x02000000 -m comment --comment \"set replay bit\" >/dev/null 2>&1" + "\n") self.file.write("${IPTABLES} -t filter -I FORWARD -p icmp ! --icmp-type 8 -m state --state RELATED -j CONNMARK --set-mark 0x02000000/0x02000000 -m comment --comment \"set replay bit\" " + "\n") self.file.write("${IPTABLES} -t filter -D FORWARD -p icmp ! --icmp-type 8 -m connmark --mark 0x02000000/0x02000000 -m state --state RELATED -j DROP -m comment --comment \"drop if replay\" >/dev/null 2>&1" + "\n") self.file.write("${IPTABLES} -t filter -I FORWARD -p icmp ! --icmp-type 8 -m connmark --mark 0x02000000/0x02000000 -m state --state RELATED -j DROP -m comment --comment \"drop if replay\" " + "\n") self.file.write("\n") # no need for ipv6 - this is only for ICSA compliance self.write_access_rules(settings) self.write_filter_rules(settings) self.file.write("\n") self.file.write("${IPTABLES} -t filter -D FORWARD -m conntrack --ctstate NEW -j DROP -m comment --comment \"drop sessions during restart\" >/dev/null 2>&1\n") self.file.write("${IPTABLES} -t filter -D INPUT -m conntrack --ctstate NEW -j DROP -m comment --comment \"drop sessions during restart\" >/dev/null 2>&1\n") self.file.write("\n") # self.file.write("# Flush IPv6 Rules" + "\n"); #self.file.write("${IP6TABLES} -t filter -F FORWARD -m comment --comment \"Flush IPv6 rules\" >/dev/null 2>&1" + "\n"); # if settings.get('blockIpv6Forwarding'): # self.file.write("# Block IPv6 Fowarding" + "\n"); # self.file.write("${IP6TABLES} -t filter -A FORWARD -j DROP -m comment --comment \"Do not allow IPv6 forwarding\" >/dev/null 2>&1" + "\n"); # self.file.write("\n"); # self.file.write("# Block IPv6 Input" + "\n"); #self.file.write("${IP6TABLES} -t filter -F INPUT -m comment --comment \"Flush IPv6 filter rules\" >/dev/null 2>&1" + "\n"); #self.file.write("${IP6TABLES} -t filter -A INPUT -p icmpv6 -j RETURN -m comment --comment \"Allow IPv6 icmp RA, solicitions, ping etc\" >/dev/null 2>&1" + "\n"); #self.file.write("${IP6TABLES} -t filter -A INPUT -j DROP -m comment --comment \"Do not allow IPv6 input\" >/dev/null 2>&1" + "\n"); # self.file.write("\n"); self.file.flush() self.file.close() print("FilterRulesManager: Wrote %s" % self.filename) return
def write_routes(self, settings, prefix): filename = prefix + self.routes_filename file_dir = os.path.dirname(filename) if not os.path.exists(file_dir): os.makedirs(file_dir) file = open(filename, "w+") file.write("#!/bin/dash") file.write("\n\n") file.write("## Auto Generated\n") file.write("## DO NOT EDIT. Changes will be overwritten.\n") file.write("\n\n") file.write("expected_ip_route_rules()" + "\n") file.write("{" + "\n") for intfId in NetworkUtil.wan_list(): file.write(" printf \"%s%03d:\\tfrom all fwmark %#x/%#x lookup uplink.%d \\n\"\n" % (self.IP_RULE_PRIORITY, intfId, intfId << self.DST_INTERFACE_SHIFT, self.DST_INTERFACE_MASK, intfId)) file.write("}" + "\n") file.write("\n\n") file.write(r""" current_ip_route_rules() { ip rule show | awk "/^%s[0-9][0-9][0-9]:/ { print }" } """ % self.IP_RULE_PRIORITY) file.write("\n\n") file.write(r""" flush_ip_route_rules() { local t_priority for t_priority in `ip rule show | awk "/^%s[0-9][0-9][0-9]:/ { sub( \":\", \"\", \\$1 ) ; print \\$1 }"`; do ip rule del priority ${t_priority} done } """ % self.IP_RULE_PRIORITY) file.write("\n\n") file.write("insert_ip_route_rules()" + "\n") file.write("{" + "\n") for intfId in NetworkUtil.wan_list(): file.write(" ip rule add priority %s%03d fwmark %#x/%#x lookup uplink.%i\n" % (self.IP_RULE_PRIORITY, intfId, intfId << self.DST_INTERFACE_SHIFT, self.DST_INTERFACE_MASK, intfId)) file.write("}" + "\n") file.write(r""" if [ "`expected_ip_route_rules | md5sum`" != "`current_ip_route_rules | md5sum`" ]; then echo "Flushing ip route rules..." flush_ip_route_rules echo "Inserting ip route rules..." insert_ip_route_rules fi """) # Write the static routes from settings if settings == None or 'staticRoutes' not in settings: print("ERROR: Missing Static Routes") else: static_routes = settings['staticRoutes'] for static_route in static_routes: for key in ['ruleId', 'nextHop', 'network', 'prefix']: if key not in static_route: print("ERROR: ignoring bad route missing key: %s\n" % key) continue if self.string_is_int(static_route['nextHop']): # if nextHop is an interfaceId interfaceId = int(static_route['nextHop']) for intf in settings['interfaces']: if intf.get('interfaceId') == interfaceId: # device route since nextHop includes alphas file.write("# Static Route %i\n" % static_route['ruleId']) file.write("ip route add %s/%s dev %s\n" % (static_route['network'], static_route['prefix'], intf.get('symbolicDev'))) file.write("if [ $? != 0 ] ; then echo \"ERROR: inserting route %i\" ; fi \n" % static_route['ruleId']) file.write("\n") else: # otherwise gateway route file.write("# Static Route %i\n" % static_route['ruleId']) file.write("ip route add %s/%s via %s\n" % (static_route['network'], static_route['prefix'], static_route['nextHop'])) file.write("if [ $? != 0 ] ; then echo \"ERROR: inserting route %i\" ; fi \n" % static_route['ruleId']) file.write("\n") file.flush() file.close() os.chmod(filename, os.stat(filename).st_mode | stat.S_IEXEC) print("RouteManager: Wrote %s" % filename) return
def write_implicit_nat_rules(self, settings): self.file.write("# Implicit NAT Rule (hairpin for port forwards)" + "\n") for intfId in NetworkUtil.interface_list(): self.file.write("${IPTABLES} -t nat -A nat-rules -m conntrack --ctstate DNAT -m connmark --mark 0x%X/0x%X -j MASQUERADE -m comment --comment \"NAT all port forwards (hairpin) (interface %s)\"" % ((intfId+(intfId << 8)), self.interfaces_mark_mask, str(intfId)) + "\n") self.file.write("\n")
def write_filter_rules_file(self, settings, prefix=""): self.filename = prefix + self.iptables_filename self.file_dir = os.path.dirname(self.filename) if not os.path.exists(self.file_dir): os.makedirs(self.file_dir) self.file = open(self.filename, "w+") self.file.write("## Auto Generated\n") self.file.write("## DO NOT EDIT. Changes will be overwritten.\n") self.file.write("\n") self.file.write("\n") self.file.write("# Create (if needed) and flush access-rules chain" + "\n") self.file.write("${IPTABLES} -t filter -N access-rules 2>/dev/null" + "\n") self.file.write( "${IPTABLES} -t filter -F access-rules >/dev/null 2>&1" + "\n") self.file.write("\n") self.file.write("${IP6TABLES} -t filter -N access-rules 2>/dev/null" + "\n") self.file.write( "${IP6TABLES} -t filter -F access-rules >/dev/null 2>&1" + "\n") self.file.write("\n") self.file.write("# Create (if needed) and flush access-rules chain" + "\n") self.file.write("${IPTABLES} -t filter -N filter-rules 2>/dev/null" + "\n") self.file.write( "${IPTABLES} -t filter -F filter-rules >/dev/null 2>&1" + "\n") self.file.write("\n") self.file.write("${IP6TABLES} -t filter -N filter-rules 2>/dev/null" + "\n") self.file.write( "${IP6TABLES} -t filter -F filter-rules >/dev/null 2>&1" + "\n") self.file.write("\n") self.file.write("# Create (if needed) and flush access-rules chain" + "\n") self.file.write("${IPTABLES} -t filter -N block-invalid 2>/dev/null" + "\n") self.file.write( "${IPTABLES} -t filter -F block-invalid >/dev/null 2>&1" + "\n") self.file.write("\n") self.file.write("${IP6TABLES} -t filter -N block-invalid 2>/dev/null" + "\n") self.file.write( "${IP6TABLES} -t filter -F block-invalid >/dev/null 2>&1" + "\n") self.file.write("\n") self.file.write("# Call access-rules chain from INPUT/filter chain" + "\n") self.file.write( "${IPTABLES} -t filter -D INPUT -m conntrack --ctstate NEW -m comment --comment \"input filter rules\" -j access-rules >/dev/null 2>&1" + "\n") self.file.write( "${IPTABLES} -t filter -A INPUT -m conntrack --ctstate NEW -m comment --comment \"input filter rules\" -j access-rules" + "\n") self.file.write("\n") self.file.write( "${IP6TABLES} -t filter -D INPUT -m conntrack --ctstate NEW -m comment --comment \"input filter rules\" -j access-rules >/dev/null 2>&1" + "\n") self.file.write( "${IP6TABLES} -t filter -A INPUT -m conntrack --ctstate NEW -m comment --comment \"input filter rules\" -j access-rules" + "\n") self.file.write("\n") self.file.write("# Call filter-rules chain from FORWARD/filter chain" + "\n") self.file.write( "${IPTABLES} -t filter -D FORWARD -m conntrack --ctstate NEW -m comment --comment \"forward filter rules\" -j filter-rules >/dev/null 2>&1" + "\n") self.file.write( "${IPTABLES} -t filter -A FORWARD -m conntrack --ctstate NEW -m comment --comment \"forward filter rules\" -j filter-rules" + "\n") self.file.write("\n") self.file.write( "${IP6TABLES} -t filter -D FORWARD -m conntrack --ctstate NEW -m comment --comment \"forward filter rules\" -j filter-rules >/dev/null 2>&1" + "\n") self.file.write( "${IP6TABLES} -t filter -A FORWARD -m conntrack --ctstate NEW -m comment --comment \"forward filter rules\" -j filter-rules" + "\n") self.file.write("\n") self.file.write("# Pass all local traffic " + "\n") self.file.write( "${IPTABLES} -t filter -D access-rules -i lo -j RETURN -m comment --comment \"Allow all local traffic\" >/dev/null 2>&1" + "\n") self.file.write( "${IPTABLES} -t filter -I access-rules -i lo -j RETURN -m comment --comment \"Allow all local traffic\"" + "\n") self.file.write("\n") self.file.write( "${IP6TABLES} -t filter -D access-rules -i lo -j RETURN -m comment --comment \"Allow all local traffic\" >/dev/null 2>&1" + "\n") self.file.write( "${IP6TABLES} -t filter -I access-rules -i lo -j RETURN -m comment --comment \"Allow all local traffic\"" + "\n") self.file.write("\n") self.file.write("# Block INVALID packets" + "\n") self.file.write( "${IPTABLES} -t filter -D block-invalid -m conntrack --ctstate INVALID -j DROP -m comment --comment \"Block INVALID packets\" >/dev/null 2>&1" + "\n") self.file.write( "${IPTABLES} -t filter -I block-invalid -m conntrack --ctstate INVALID -j DROP -m comment --comment \"Block INVALID packets\" " + "\n") self.file.write( "${IPTABLES} -t filter -D block-invalid -m conntrack --ctstate INVALID -j NFLOG --nflog-prefix \"invalid_blocked\" -m comment --comment \"nflog on invalid\" >/dev/null 2>&1\n" ) self.file.write( "${IPTABLES} -t filter -I block-invalid -m conntrack --ctstate INVALID -j NFLOG --nflog-prefix \"invalid_blocked\" -m comment --comment \"nflog on invalid\"\n" ) for intfId in NetworkUtil.interface_list(): self.file.write( "${IPTABLES} -t filter -I block-invalid -m mark --mark 0x%X/0x%X -j RETURN -m comment --comment \"Allow INVALID hairpin traffic (interface %s)\"" % ((intfId + (intfId << 8)), self.interfaces_mark_mask, str(intfId)) + "\n") self.file.write( "${IPTABLES} -t filter -I block-invalid -m mark --mark 0xfe00/0xff00 -j RETURN -m comment --comment \"Allow INVALID to local sockets (interface 0xfe)\"" + "\n") self.file.write("\n") self.file.write("# Block INVALID packets" + "\n") self.file.write( "${IP6TABLES} -t filter -D block-invalid -m conntrack --ctstate INVALID -j DROP -m comment --comment \"Block INVALID packets\" >/dev/null 2>&1" + "\n") self.file.write( "${IP6TABLES} -t filter -I block-invalid -m conntrack --ctstate INVALID -j DROP -m comment --comment \"Block INVALID packets\" " + "\n") # disabled because I don't think the nflog daemon handles IPv6 currently #self.file.write("${IP6TABLES} -t filter -D block-invalid -m conntrack --ctstate INVALID -j NFLOG --nflog-prefix \"invalid_blocked\" -m comment --comment \"nflog on invalid\" >/dev/null 2>&1\n"); #self.file.write("${IP6TABLES} -t filter -I block-invalid -m conntrack --ctstate INVALID -j NFLOG --nflog-prefix \"invalid_blocked\" -m comment --comment \"nflog on invalid\"\n"); for intfId in NetworkUtil.interface_list(): self.file.write( "${IP6TABLES} -t filter -I block-invalid -m mark --mark 0x%X/0x%X -j RETURN -m comment --comment \"Allow INVALID hairpin traffic (interface %s)\"" % ((intfId + (intfId << 8)), self.interfaces_mark_mask, str(intfId)) + "\n") self.file.write( "${IP6TABLES} -t filter -I block-invalid -m mark --mark 0xfe00/0xff00 -j RETURN -m comment --comment \"Allow INVALID to local sockets (interface 0xfe)\"" + "\n") self.file.write("\n") if settings.get('blockInvalidPackets'): self.file.write("# Block INVALID packets" + "\n") self.file.write( "${IPTABLES} -t filter -D INPUT -m conntrack --ctstate INVALID -j block-invalid -m comment --comment \"Block INVALID\" >/dev/null 2>&1" + "\n") self.file.write( "${IPTABLES} -t filter -A INPUT -m conntrack --ctstate INVALID -j block-invalid -m comment --comment \"Block INVALID\"" + "\n") self.file.write("\n") self.file.write("# Block INVALID packets" + "\n") self.file.write( "${IPTABLES} -t filter -D FORWARD -m conntrack --ctstate INVALID -j block-invalid -m comment --comment \"Block INVALID\" >/dev/null 2>&1" + "\n") self.file.write( "${IPTABLES} -t filter -A FORWARD -m conntrack --ctstate INVALID -j block-invalid -m comment --comment \"Block INVALID\"" + "\n") self.file.write("\n") self.file.write("# Pass all RELATED traffic " + "\n") self.file.write( "${IPTABLES} -t filter -D access-rules -m conntrack --ctstate RELATED -j RETURN -m comment --comment \"Allow RELATED traffic\" >/dev/null 2>&1" + "\n") self.file.write( "${IPTABLES} -t filter -I access-rules -m conntrack --ctstate RELATED -j RETURN -m comment --comment \"Allow RELATED traffic\"" + "\n") self.file.write("\n") self.file.write( "${IP6TABLES} -t filter -D access-rules -m conntrack --ctstate RELATED -j RETURN -m comment --comment \"Allow RELATED traffic\" >/dev/null 2>&1" + "\n") self.file.write( "${IP6TABLES} -t filter -I access-rules -m conntrack --ctstate RELATED -j RETURN -m comment --comment \"Allow RELATED traffic\"" + "\n") self.file.write("\n") self.file.write("# Pass all RELATED traffic " + "\n") self.file.write( "${IPTABLES} -t filter -D filter-rules -m conntrack --ctstate RELATED -j RETURN -m comment --comment \"Allow RELATED traffic\" >/dev/null 2>&1" + "\n") self.file.write( "${IPTABLES} -t filter -I filter-rules -m conntrack --ctstate RELATED -j RETURN -m comment --comment \"Allow RELATED traffic\"" + "\n") self.file.write("\n") self.file.write( "${IP6TABLES} -t filter -D filter-rules -m conntrack --ctstate RELATED -j RETURN -m comment --comment \"Allow RELATED traffic\" >/dev/null 2>&1" + "\n") self.file.write( "${IP6TABLES} -t filter -I filter-rules -m conntrack --ctstate RELATED -j RETURN -m comment --comment \"Allow RELATED traffic\"" + "\n") self.file.write("\n") # This is commented out because we have explicit rules to handle admin & blockpages in the input rules. # self.file.write("# Pass all port forwarded traffic (for block pages & admin) " + "\n"); # self.file.write("${IPTABLES} -t filter -D access-rules -m conntrack --ctstate DNAT -j RETURN -m comment --comment \"Allow port forwarded traffic\" >/dev/null 2>&1" + "\n"); # self.file.write("${IPTABLES} -t filter -I access-rules -m conntrack --ctstate DNAT -j RETURN -m comment --comment \"Allow port forwarded traffic\"" + "\n"); # self.file.write("\n"); self.file.write("# Pass all reinjected TCP traffic " + "\n") self.file.write( "${IPTABLES} -t filter -D access-rules -i utun -j RETURN -m comment --comment \"Allow all reinjected traffic\" >/dev/null 2>&1" + "\n") self.file.write( "${IPTABLES} -t filter -I access-rules -i utun -j RETURN -m comment --comment \"Allow all reinjected traffic\"" + "\n") self.file.write("\n") self.file.write( "${IP6TABLES} -t filter -D access-rules -i utun -j RETURN -m comment --comment \"Allow all reinjected traffic\" >/dev/null 2>&1" + "\n") self.file.write( "${IP6TABLES} -t filter -I access-rules -i utun -j RETURN -m comment --comment \"Allow all reinjected traffic\"" + "\n") self.file.write("\n") if settings.get('blockReplayPackets'): self.file.write("# Block Replay packets" + "\n") # more info in bug #12357 #12358 #12359 self.file.write( "${IPTABLES} -t filter -D FORWARD -p tcp --tcp-flags RST RST -j CONNMARK --set-mark 0x02000000/0x02000000 -m comment --comment \"set replay bit\" >/dev/null 2>&1" + "\n") self.file.write( "${IPTABLES} -t filter -I FORWARD -p tcp --tcp-flags RST RST -j CONNMARK --set-mark 0x02000000/0x02000000 -m comment --comment \"set replay bit\" " + "\n") self.file.write( "${IPTABLES} -t filter -D FORWARD -p tcp --tcp-flags RST RST -m connmark --mark 0x02000000/0x02000000 -m state --state RELATED -j DROP -m comment --comment \"drop if replay\" >/dev/null 2>&1" + "\n") self.file.write( "${IPTABLES} -t filter -I FORWARD -p tcp --tcp-flags RST RST -m connmark --mark 0x02000000/0x02000000 -m state --state RELATED -j DROP -m comment --comment \"drop if replay\" " + "\n") self.file.write( "${IPTABLES} -t filter -D FORWARD -p icmp ! --icmp-type 8 -m state --state RELATED -j CONNMARK --set-mark 0x02000000/0x02000000 -m comment --comment \"set replay bit\" >/dev/null 2>&1" + "\n") self.file.write( "${IPTABLES} -t filter -I FORWARD -p icmp ! --icmp-type 8 -m state --state RELATED -j CONNMARK --set-mark 0x02000000/0x02000000 -m comment --comment \"set replay bit\" " + "\n") self.file.write( "${IPTABLES} -t filter -D FORWARD -p icmp ! --icmp-type 8 -m connmark --mark 0x02000000/0x02000000 -m state --state RELATED -j DROP -m comment --comment \"drop if replay\" >/dev/null 2>&1" + "\n") self.file.write( "${IPTABLES} -t filter -I FORWARD -p icmp ! --icmp-type 8 -m connmark --mark 0x02000000/0x02000000 -m state --state RELATED -j DROP -m comment --comment \"drop if replay\" " + "\n") self.file.write("\n") # no need for ipv6 - this is only for ICSA compliance self.write_access_rules(settings) self.write_filter_rules(settings) self.file.write("\n") self.file.write( "${IPTABLES} -t filter -D FORWARD -m conntrack --ctstate NEW -j DROP -m comment --comment \"drop sessions during restart\" >/dev/null 2>&1\n" ) self.file.write( "${IPTABLES} -t filter -D INPUT -m conntrack --ctstate NEW -j DROP -m comment --comment \"drop sessions during restart\" >/dev/null 2>&1\n" ) self.file.write("\n") # self.file.write("# Flush IPv6 Rules" + "\n"); #self.file.write("${IP6TABLES} -t filter -F FORWARD -m comment --comment \"Flush IPv6 rules\" >/dev/null 2>&1" + "\n"); # if settings.get('blockIpv6Forwarding'): # self.file.write("# Block IPv6 Fowarding" + "\n"); # self.file.write("${IP6TABLES} -t filter -A FORWARD -j DROP -m comment --comment \"Do not allow IPv6 forwarding\" >/dev/null 2>&1" + "\n"); # self.file.write("\n"); # self.file.write("# Block IPv6 Input" + "\n"); #self.file.write("${IP6TABLES} -t filter -F INPUT -m comment --comment \"Flush IPv6 filter rules\" >/dev/null 2>&1" + "\n"); #self.file.write("${IP6TABLES} -t filter -A INPUT -p icmpv6 -j RETURN -m comment --comment \"Allow IPv6 icmp RA, solicitions, ping etc\" >/dev/null 2>&1" + "\n"); #self.file.write("${IP6TABLES} -t filter -A INPUT -j DROP -m comment --comment \"Do not allow IPv6 input\" >/dev/null 2>&1" + "\n"); # self.file.write("\n"); self.file.flush() self.file.close() print("FilterRulesManager: Wrote %s" % self.filename) return