Mikrotik firewall filter: скрипт генерирующий основу для политики фильтрации

—

от автора

Кто хоть раз писал политику фильрации firewall знает, что это дело не простое и сопряжено с кучей ошибок, когда колличество сетевых зон больше 2-х. В этой сутации вам поможет скрипт из этой статьи.

Введение

Под сетевой зоной я подразумеваю совокупность интерфейсов или IP адресов, для которых применяется правило фильтрации. В моем скрипте IP адреса зоны закреплены за интерфейсом. То есть, если мы ожидаем «доверенные» IP адреса из локальной сети, то будет странно, если соответствующие соединения прилетят к нам от провайдера.

Как оно работает

Все вертится вокруг описания зон, где мы задаем как они между собой взаимодействуют.
В моей конфигурации, если не заданы другие правила, весь трафик будет сброшен с правилом DROP, поэтому мы будем задавать правила ACCEPT и REJECT.
Далее скрипт в цикле проходит по всем описаниям зон и создает:

  • Списки интерфейсов IF-<имя зоны>
  • Списки адресов IP-<имя зоны>
  • Задает дефолтовую и немного мной дополненую конфигурацию filter, mangle и raw

IP зона назначения трафика от интерфейсной отличается тем, что её имени нет в разделе для интерфейсов. Таким образом скрипт и понимает, где у нас назначение ip, а где интерфейс.

Переменные

  • gping — Разрешить ping во всех направлениях и на пересылке. Иными словами, пинговать можно будет даже то, что было закрыто другими правилами в filter. Включать по желанию 😉
  • debug — Ставит в самое начало корневых цепочек ACCEPT правило, что делает все остальные правила бесполезными. Очень полезно на этапе отладки правил. Делаете политику как вы хотите, включаете Safe Mode, а потом эти правила отключаете. Если роутер стал недоступен, то уже через 10 сек правила будут включены опять и вы сможете подумать, а в чем вы ошиблись?

Описание зон

Само описание разделено на два блока: интерфейсы и ip адреса. Для интерфейсов есть специальные переменные:

  • is_wan: добавляет правила для обработки тунелей и DNS
  • is_lan: добавляет правила для ответа на DHCP и DNS
  • mss: добавляет правила корректировки mss для туннельных интерфейсов, если встроенные средства вас не устраивают

Так-же есть две специальные зоны: rt, это сам роутер, и all, как не трудно догадаться «любое направление», all не может быть указан в качестве источника трафика.
Основное действие скрипта, это создание серии правил jump с фильтрацией по источнику и назначению трафика, которые терминируются правилом с ACCEPT или REJECT.
Описание зоны может быть редуцированно, как в примере для ISP и rt (должно быть всегда).
Если вы хотите терминировать цепочку своим правилом, то в описание зоны просто вместо accept или reject впишите custom (или что угодно), тогда цепочка jump-ов не будет завершена никаким правилом, а вы сможете создать его самостоятельно.

Пояснение правил из скрипта

Зоны

:local gping 1 :local debug 0 :local zones { 	"if"={ 		"ISP"={ 			"is_wan"=1; 		}; 		"LAN"={ 			"is_lan"=1; 			policy={  				"all"="accept"; 			}; 		}; 		"TUN"={ 			mss=1400; 		}; 		"rt"={}; 	}; 	"ip"={ 		"rt"={ 			policy={ 				"all"="accept"  			}; 		}; 		"TUN"={ 			"Staff"={ 				"Server"="accept"; 			}; 			"Manager"={ 				"all"="accept"; 			}; 		}; 		"ISP"={ 			"Trusted"={ 				"rt"="accept"; 			}; 		}; 	}; } 

Задано 4-е зоны для интерфейсов, одна из которых, обязательная rt:

  • ISP — для провайдера, поэтому указано создавать дополнительные правила для некоторых протоколов.
  • LAN — для локальной сети, ей заданы правила для lan и есть общее разрешающие действие на любые направления.
  • TUN — для собственно тунелей, указана корректировка MSS.

B 3-и ip зоны:

  • Staff и Manager на интерфейсах TUN:
    • Staff — имеет доступ только к ip зоне Server
    • Manager — могут куда угодно

  • Trusted на интерфейсе ISP имеет доступ к роутеру

gen-filter

# may/01/2020 10:00:00 by RouterOS 6.46.6 # RoS filter generator v 0.9.1  :local gping 0 :local debug 1 :local zones { 	"if"={ 		"ISP"={ 			"is_wan"=1; 		}; 		"LAN"={ 			"is_lan"=1; 			policy={  				"all"="accept"; 			}; 		}; 		"TUN"={ 			mss=1400; 		}; 		"rt"={}; 	}; 	"ip"={ 		"rt"={ 			policy={ 				"all"="accept"  			}; 		}; 		"TUN"={ 			"Staff"={ 				"Server"="accept"; 			}; 			"Manager"={ 				"all"="accept"; 			}; 		}; 		"ISP"={ 			"Trusted"={ 				"rt"="accept"; 			}; 		}; 	}; } /ip firewall raw add action=notrack chain=prerouting ipsec-policy=in,ipsec comment="Notrack ipsec" add action=notrack chain=prerouting dst-address-type=multicast comment="Notrack multicast" /ip firewall filter :if ( ($debug)=0 ) do={ 	add action=accept chain=forward comment=DEBUG!!! disabled=yes 	add action=accept chain=input comment=DEBUG!!! disabled=yes 	add action=accept chain=output comment=DEBUG!!! disabled=yes } else={ 	add action=accept chain=forward comment=DEBUG!!! 	add action=accept chain=input comment=DEBUG!!! 	add action=accept chain=output comment=DEBUG!!! } add action=accept chain=input comment="defconf: accept to local loopback (for CAPsMAN)" dst-address=127.0.0.1 dst-port=5246,5247 protocol=udp src-address-type=local add action=accept chain=input comment="defconf: accept established,related,untracked" connection-state=established,related,untracked add action=drop chain=input comment="defconf: drop invalid" connection-state=invalid add action=jump chain=input comment="defconf: new input" jump-target=in-new add action=drop chain=input comment="defconf: drop all not allowed" add action=accept chain=output comment="defconf: accept established,related,untracked" connection-state=established,related,untracked add action=jump chain=output comment="defconf: new output" jump-target=out-new add action=drop chain=output comment="defconf: drop all not allowed" add action=accept chain=forward comment="defconf: accept in ipsec policy" ipsec-policy=in,ipsec add action=accept chain=forward comment="defconf: accept out ipsec policy" ipsec-policy=out,ipsec add action=fasttrack-connection chain=forward comment="defconf: fasttrack" connection-mark=no-mark connection-state=established,related add action=accept chain=forward comment="defconf: accept established,related, untracked" connection-state=established,related,untracked add action=drop chain=forward comment="defconf: drop invalid" connection-state=invalid add action=jump chain=forward comment="defconf: new forward" jump-target=fw-new add action=accept chain=new-FORWARD comment="defconf: Accept all forward DSTNATed" connection-nat-state=dstnat add action=drop chain=forward comment="defconf: drop all not allowed for forward" :if ( ($gping)=1 ) do={ 	add action=accept chain=WAN2RT-STD-PROTO comment=ICMP protocol=icmp disabled=yes } else={ 	add action=accept chain=WAN2RT-STD-PROTO comment=ICMP protocol=icmp } add action=accept chain=WAN2RT-STD-PROTO comment=GRE ipsec-policy=in,ipsec protocol=gre add action=accept chain=WAN2RT-STD-PROTO comment=IPSec protocol=ipsec-esp add action=accept chain=WAN2RT-STD-PROTO comment=IPSec protocol=ipsec-ah add action=accept chain=WAN2RT-STD-PROTO comment="IPSec encapsulated" dst-port=500,4500 protocol=udp add action=accept chain=WAN2RT-STD-PROTO comment=L2TP dst-port=1701 ipsec-policy=in,ipsec protocol=udp add action=accept chain=WAN2RT-STD-PROTO comment=PPtP dst-port=1723 protocol=tcp add action=accept chain=LAN2RT-STD-PROTO comment=DNS dst-port=53 protocol=tcp add action=accept chain=LAN2RT-STD-PROTO comment=NTP,DNS,DHCP dst-port=53,123,67-68 protocol=udp add action=accept chain=LAN2RT-STD-PROTO comment=DHCP dst-address-type=broadcast dst-port=67-68 protocol=udp add action=accept chain=RT2WAN-STD-PROTO comment=DNS dst-port=53 protocol=tcp add action=accept chain=RT2WAN-STD-PROTO comment=NTP,DNS dst-port=53,123 protocol=udp add action=reject chain=RT2WAN-STD-PROTO comment=GRE ipsec-policy=out,none protocol=gre reject-with=icmp-admin-prohibited add action=reject chain=RT2WAN-STD-PROTO comment=L2TP dst-port=1701 ipsec-policy=out,none protocol=udp reject-with=icmp-admin-prohibited :if ( ($gping)=1 ) do={ 	add action=accept chain=fw-new comment=ICMP protocol=icmp 	add action=accept chain=in-new comment=ICMP protocol=icmp 	add action=accept chain=out-new comment=ICMP protocol=icmp } else={ 	add action=accept chain=fw-new comment=ICMP protocol=icmp disabled=yes 	add action=accept chain=in-new comment=ICMP protocol=icmp disabled=yes 	add action=accept chain=out-new comment=ICMP protocol=icmp disabled=yes } /ip firewall filter :foreach zone,conf in=($zones->"if") do={ 	:if ( ($zone)!="rt" ) do={ 		:if ( [/interface list print count-only where name=("IF-".$zone)] = 0) do={ 			/interface list add name=("IF-".$zone) 		} 		add action=jump chain=fw-new in-interface-list=("IF-".$zone) comment=("Fwd plc from if ".$zone) jump-target=("fw-plc-s:".$zone) 		add action=jump chain=in-new in-interface-list=("IF-".$zone) comment=("In plc for if ".$zone) jump-target=("in-plc-s:".$zone) 	} else={ 		add action=jump chain=out-new comment=("Out plc for rt") jump-target="out-plc-s:rt" 	}	 } :foreach zone,conf in=($zones->"if") do={ 	:if ( ($zone)!="rt" && ($zone)!="all") do={ 		:if ( ($conf->"is_lan")=1 || ($conf->"is_wan")=1 ) do={ 			add action=jump chain=("in-plc-s:".$zone) comment=("In plc for if ".$zone." to rt") jump-target=("in-plc-s:".$zone.">rt") 		} 		:if ( ($conf->"is_wan")=1) do={ 			add action=jump chain=("in-plc-s:".$zone.">rt") comment=("In Allow plc for STD WAN PROTO from".$zone) in-interface-list=("IF-".$zone) jump-target=WAN2RT-STD-PROTO 			add action=jump chain="out-plc-s:rt" out-interface-list=("IF-".$zone) comment=("Out Allow plc for STD WAN PROTO to ".$zone) jump-target=RT2WAN-STD-PROTO 		}	 		:if ( ($conf->"is_lan")=1) do={ 			add action=jump chain=("in-plc-s:".$zone.">rt") in-interface-list=("IF-".$zone) comment=("In Allow plc for STD LAN PROTO from".$zone) jump-target=LAN2RT-STD-PROTO 		}	 		:if ( [:len ($conf->"mss")]!=0 ) do={ 			/ip firewall mangle add action=change-mss chain=forward in-interface-list=("IF-".$zone) new-mss=($conf->"mss") passthrough=yes protocol=tcp tcp-flags=syn tcp-mss=(($conf->"mss"+1)."-65535") comment=("Fix mss on tunel ".$zone) 			/ip firewall mangle add action=change-mss chain=forward out-interface-list=("IF-".$zone) new-mss=($conf->"mss") passthrough=yes protocol=tcp tcp-flags=syn tcp-mss=(($conf->"mss"+1)."-65535") comment=("Fix mss on tunel ".$zone) 		} 		:foreach src,val in=(($zones->"ip")->$"zone") do={ 			:foreach tgt,policy in=$val do={ 				:if ( ($tgt)!="rt" && ($tgt)!="all") do={ 					:if ( [:len (($zones->"if")->$"tgt")]=0 ) do={ 						add action=jump chain=("fw-plc-s:".$zone) src-address-list=("IP-".$src) dst-address-list=("IP-".$tgt) comment=("Fwd plc from if ".$zone." & ip ".$src." to ".$tgt) jump-target=("fw-plc-s:".$zone."&".$src.">".$tgt) 					} else={ 						add action=jump chain=("fw-plc-s:".$zone) src-address-list=("IP-".$src) out-interface-list=("IF-".$tgt) comment=("Fwd plc from if ".$zone." & ip ".$src." to ".$tgt) jump-target=("fw-plc-s:".$zone."&".$src.">".$tgt) 					} 					:if ( ($policy)="accept") do={ 						add action=accept chain=("fw-plc-s:".$zone."&".$src.">".$tgt) comment=("Fwd plc from if ".$zone." & ip ".$src." Accept to ".$tgt) 					} 					:if ( ($policy)="reject") do={ 						add action=reject chain=("fw-plc-s:".$zone."&".$src.">".$tgt) comment=("Fwd plc from if ".$zone." & ip ".$src." Reject to ".$tgt) 					} 				} 				:if ( ($tgt)="rt" ) do={ 					add action=jump chain=("in-plc-s:".$zone) src-address-list=("IP-".$src) comment=("In plc for if ".$zone." & ip ".$src." to rt") jump-target=("in-plc-s:".$zone."&".$src.">rt") 					:if ( ($policy)="accept") do={ 						add action=accept chain=("in-plc-s:".$zone."&".$src.">rt") comment=("In plc for if ".$zone." & ip ".$src." Accept to rt") 					} 					:if ( ($policy)="reject") do={ 						add action=reject chain=("in-plc-s:".$zone."&".$src.">rt") comment=("In plc for if ".$zone." & ip ".$src." Accept to rt") 					} 				} 				:if ( ($tgt)="all" ) do={ 					add action=jump chain=("fw-plc-s:".$zone) src-address-list=("IP-".$src) comment=("Fwd plc from if ".$zone." & ip ".$src." to All") jump-target=("fw-plc-s:".$zone."&".$src.">all") 					add action=jump chain=("in-plc-s:".$zone) src-address-list=("IP-".$src) comment=("In plc for if ".$zone." & ip ".$src." to All") jump-target=("in-plc-s:".$zone."&".$src.">all") 					:if ( ($policy)="accept") do={ 						add action=accept chain=("fw-plc-s:".$zone."&".$src.">all") comment=("Fwd plc from if ".$zone." & ip ".$src." Accept to All") 						add action=accept chain=("in-plc-s:".$zone."&".$src.">all") comment=("In plc from if ".$zone." & ip ".$src." Accept to All") 					} 					:if ( ($policy)="reject") do={ 						add action=reject chain=("fw-plc-s:".$zone."&".$src.">all") comment=("Fwd plc from if ".$zone." & ip ".$src." Reject to All") 						add action=reject chain=("in-plc-s:".$zone."&".$src.">all") comment=("In plc from if ".$zone." & ip ".$src." Reject to All") 					} 				} 			} 		} 		:foreach tgt,policy in=($conf->"policy") do={ 			:if ( ($tgt)!="rt" && ($tgt)!="all") do={ 				:if ( [:len (($zones->"if")->$"tgt")]=0 ) do={ 					add action=jump chain=("fw-plc-s:".$zone) dst-address-list=("IP-".$tgt) comment=("Fwd plc from if ".$zone." to ".$tgt) jump-target=("fw-plc-s:".$zone.">".$tgt) 				} else={ 					add action=jump chain=("fw-plc-s:".$zone) out-interface-list=("IF-".$tgt) comment=("Fwd plc from if ".$zone." to ".$tgt) jump-target=("fw-plc-s:".$zone.">".$tgt) 				} 				:if ( ($policy)="accept") do={ 					add action=accept chain=("fw-plc-s:".$zone.">".$tgt) comment=("Fwd plc from if ".$zone." Accept to ".$tgt) 				} 				:if ( ($policy)="reject") do={ 					add action=reject chain=("fw-plc-s:".$zone.">".$tgt) comment=("Fwd plc from if ".$zone." Reject to ".$tgt) 				} 			} 			:if ( ($tgt)="rt" ) do={ 				:if ( ($conf->"is_lan")!=1 && ($conf->"is_wan")!=1 ) do={ 					add action=jump chain=("in-plc-s:".$zone) comment=("In plc for if ".$zone." to rt") jump-target=("in-plc-s:".$zone.">rt") 				} 				:if ( ($policy)="accept") do={ 					add action=accept chain=("in-plc-s:".$zone.">rt") comment=("In plc for if ".$zone." Accept to rt") 				} 				:if ( ($policy)="reject") do={ 					add action=reject chain=("in-plc-s:".$zone.">rt") comment=("In plc for if ".$zone." Reject to rt") 				} 			} 			:if ( ($tgt)="all" ) do={ 				add action=jump chain=("fw-plc-s:".$zone) comment=("Fwd plc from if ".$zone." to All") jump-target=("fw-plc-s:".$zone.">all") 				add action=jump chain=("in-plc-s:".$zone) comment=("In plc for if ".$zone." to All") jump-target=("in-plc-s:".$zone.">all") 				:if ( ($policy)="accept") do={ 					add action=accept chain=("fw-plc-s:".$zone.">all") comment=("Fwd plc from if ".$zone." Accept to All") 					add action=accept chain=("in-plc-s:".$zone.">all") comment=("In plc from if ".$zone." Accept to All") 				} 				:if ( ($policy)="reject") do={ 					add action=reject chain=("fw-plc-s:".$zone.">all") comment=("Fwd plc from if ".$zone." Reject to All") 					add action=reject chain=("in-plc-s:".$zone.">all") comment=("In plc from if ".$zone." Reject to All") 				} 			} 		} 	} } 

Заключение

Данный скрипт мне помог сильно облегчить настройку сложных политик, однако, ошибки в нем все-же могут быть. Перед применением проконсультируйтесь со специалистом. В случае обнаружения побочных явлений, пишите, будем исправлять.

ссылка на оригинал статьи https://habr.com/ru/post/500148/