@@ -106,6 +106,7 @@ CUSTOM_IP=""
106106FAKE_CERT_LEN=2048
107107PROXY_PROTOCOL=" false"
108108AD_TAG=" "
109+ GEOBLOCK_MODE=" blacklist"
109110BLOCKLIST_COUNTRIES=" "
110111MASKING_ENABLED=" true"
111112MASKING_HOST=" "
@@ -573,6 +574,7 @@ PROXY_PROTOCOL='${PROXY_PROTOCOL}'
573574AD_TAG='${AD_TAG} '
574575
575576# Geo-Blocking
577+ GEOBLOCK_MODE='${GEOBLOCK_MODE} '
576578BLOCKLIST_COUNTRIES='${BLOCKLIST_COUNTRIES} '
577579
578580# Traffic Masking
@@ -619,7 +621,7 @@ load_settings() {
619621 # Whitelist of allowed keys
620622 case " $key " in
621623 PROXY_PORT|PROXY_METRICS_PORT|PROXY_DOMAIN|PROXY_CONCURRENCY|\
622- PROXY_CPUS|PROXY_MEMORY|CUSTOM_IP|FAKE_CERT_LEN|PROXY_PROTOCOL|AD_TAG|BLOCKLIST_COUNTRIES|\
624+ PROXY_CPUS|PROXY_MEMORY|CUSTOM_IP|FAKE_CERT_LEN|PROXY_PROTOCOL|AD_TAG|GEOBLOCK_MODE| BLOCKLIST_COUNTRIES|\
623625 MASKING_ENABLED|MASKING_HOST|MASKING_PORT|\
624626 TELEGRAM_ENABLED|TELEGRAM_BOT_TOKEN|TELEGRAM_CHAT_ID|\
625627 TELEGRAM_INTERVAL|TELEGRAM_ALERTS_ENABLED|TELEGRAM_SERVER_LABEL|\
@@ -636,6 +638,7 @@ load_settings() {
636638 [[ " $FAKE_CERT_LEN " =~ ^[0-9]+$ ]] && [ " $FAKE_CERT_LEN " -ge 512 ] || FAKE_CERT_LEN=2048
637639 [[ " $PROXY_CONCURRENCY " =~ ^[0-9]+$ ]] || PROXY_CONCURRENCY=8192
638640 [[ " $PROXY_PROTOCOL " == " true" ]] || PROXY_PROTOCOL=" false"
641+ [[ " $GEOBLOCK_MODE " == " whitelist" ]] || GEOBLOCK_MODE=" blacklist"
639642 [[ " $TELEGRAM_INTERVAL " =~ ^[0-9]+$ ]] || TELEGRAM_INTERVAL=6
640643 [[ " $TELEGRAM_CHAT_ID " =~ ^-? [0-9]+$ ]] || TELEGRAM_CHAT_ID=" "
641644}
@@ -2679,32 +2682,63 @@ _apply_country_rules() {
26792682 awk -v s=" $setname " ' NF && !/^#/ { print "add " s " " $1 }' " $cache_file " \
26802683 | ipset restore -exist
26812684
2682- # Add iptables DROP rule if not already present
2683- if ! iptables -C INPUT -m set --match-set " $setname " src \
2684- -p tcp --dport " $PROXY_PORT " \
2685- -m comment --comment " $GEOBLOCK_COMMENT " -j DROP 2> /dev/null; then
2686- iptables -I INPUT -m set --match-set " $setname " src \
2685+ if [ " $GEOBLOCK_MODE " = " whitelist" ]; then
2686+ # Whitelist: ACCEPT matching countries
2687+ if ! iptables -C INPUT -m set --match-set " $setname " src \
26872688 -p tcp --dport " $PROXY_PORT " \
2688- -m comment --comment " $GEOBLOCK_COMMENT " -j DROP
2689+ -m comment --comment " $GEOBLOCK_COMMENT " -j ACCEPT 2> /dev/null; then
2690+ iptables -I INPUT -m set --match-set " $setname " src \
2691+ -p tcp --dport " $PROXY_PORT " \
2692+ -m comment --comment " $GEOBLOCK_COMMENT " -j ACCEPT
2693+ fi
2694+ else
2695+ # Blacklist: DROP matching countries
2696+ if ! iptables -C INPUT -m set --match-set " $setname " src \
2697+ -p tcp --dport " $PROXY_PORT " \
2698+ -m comment --comment " $GEOBLOCK_COMMENT " -j DROP 2> /dev/null; then
2699+ iptables -I INPUT -m set --match-set " $setname " src \
2700+ -p tcp --dport " $PROXY_PORT " \
2701+ -m comment --comment " $GEOBLOCK_COMMENT " -j DROP
2702+ fi
26892703 fi
26902704
2691- log_success " Geo-blocking active for ${code^^} (port ${PROXY_PORT} )"
2705+ log_success " Geo-${GEOBLOCK_MODE} active for ${code^^} (port ${PROXY_PORT} )"
26922706}
26932707
26942708# Remove iptables rules and ipset for one country
26952709_remove_country_rules () {
26962710 local code=" $1 "
26972711 local setname=" ${GEOBLOCK_IPSET_PREFIX}${code} "
26982712
2699- # Remove iptables rule
2713+ # Remove iptables rule (try both DROP and ACCEPT for mode compatibility)
27002714 iptables -D INPUT -m set --match-set " $setname " src \
27012715 -p tcp --dport " $PROXY_PORT " \
27022716 -m comment --comment " $GEOBLOCK_COMMENT " -j DROP 2> /dev/null || true
2717+ iptables -D INPUT -m set --match-set " $setname " src \
2718+ -p tcp --dport " $PROXY_PORT " \
2719+ -m comment --comment " $GEOBLOCK_COMMENT " -j ACCEPT 2> /dev/null || true
27032720
27042721 # Destroy ipset
27052722 ipset destroy " $setname " 2> /dev/null || true
27062723}
27072724
2725+ # Remove whitelist default-DROP rule
2726+ _remove_default_drop () {
2727+ iptables -D INPUT -p tcp --dport " $PROXY_PORT " \
2728+ -m comment --comment " ${GEOBLOCK_COMMENT} -default" -j DROP 2> /dev/null || true
2729+ }
2730+
2731+ # Add whitelist default-DROP rule if in whitelist mode and countries exist
2732+ _ensure_default_drop () {
2733+ [ " $GEOBLOCK_MODE " = " whitelist" ] || return 0
2734+ [ -n " $BLOCKLIST_COUNTRIES " ] || return 0
2735+ if ! iptables -C INPUT -p tcp --dport " $PROXY_PORT " \
2736+ -m comment --comment " ${GEOBLOCK_COMMENT} -default" -j DROP 2> /dev/null; then
2737+ iptables -A INPUT -p tcp --dport " $PROXY_PORT " \
2738+ -m comment --comment " ${GEOBLOCK_COMMENT} -default" -j DROP
2739+ fi
2740+ }
2741+
27082742# Reapply all saved geoblock rules (called on proxy start)
27092743geoblock_reapply_all () {
27102744 [ -z " $BLOCKLIST_COUNTRIES " ] && return 0
@@ -2718,13 +2752,16 @@ geoblock_reapply_all() {
27182752 _apply_country_rules " $code " & > /dev/null || true
27192753 fi
27202754 done
2755+
2756+ # Whitelist mode: add default DROP for proxy port at the end (after all ACCEPTs)
2757+ _ensure_default_drop
27212758}
27222759
27232760# Remove ALL mtproxymax geoblock rules (called on uninstall)
27242761geoblock_remove_all () {
2725- # Remove all tagged iptables rules
2762+ # Remove all tagged iptables rules (both geoblock and geoblock-default)
27262763 if command -v iptables & > /dev/null; then
2727- iptables-save 2> /dev/null | grep -- " --comment ${GEOBLOCK_COMMENT} " | \
2764+ iptables-save 2> /dev/null | grep -E -- " --comment ${GEOBLOCK_COMMENT} (-default)? " | \
27282765 sed ' s/^-A/-D/' | while IFS= read -r rule; do
27292766 iptables $rule 2> /dev/null || true
27302767 done
@@ -2749,11 +2786,13 @@ show_geoblock_menu() {
27492786 clear_screen
27502787 draw_header " GEO-BLOCKING"
27512788 echo " "
2752- echo -e " ${BOLD} Current blocklist:${NC} ${BLOCKLIST_COUNTRIES:- ${DIM} none${NC} } "
2789+ echo -e " ${BOLD} Mode:${NC} ${GEOBLOCK_MODE} "
2790+ echo -e " ${BOLD} Countries:${NC} ${BLOCKLIST_COUNTRIES:- ${DIM} none${NC} } "
27532791 echo " "
27542792 echo -e " ${DIM} [1]${NC} Add country"
27552793 echo -e " ${DIM} [2]${NC} Remove country"
27562794 echo -e " ${DIM} [3]${NC} Clear all"
2795+ echo -e " ${DIM} [4]${NC} Toggle mode (blacklist/whitelist)"
27572796 echo -e " ${DIM} [0]${NC} Back"
27582797
27592798 local choice
@@ -2771,12 +2810,13 @@ show_geoblock_menu() {
27712810 code=$( echo " $code " | tr ' [:upper:]' ' [:lower:]' )
27722811 if [[ " $code " =~ ^[a-z]{2}$ ]]; then
27732812 if echo " ,$BLOCKLIST_COUNTRIES ," | grep -q " ,${code} ," ; then
2774- log_info " Country '${code} ' is already blocked "
2813+ log_info " Country '${code} ' is already in the list "
27752814 else
27762815 _ensure_ipset && _download_country_cidrs " $code " && {
27772816 [ -z " $BLOCKLIST_COUNTRIES " ] && BLOCKLIST_COUNTRIES=" $code " || BLOCKLIST_COUNTRIES=" ${BLOCKLIST_COUNTRIES} ,${code} "
27782817 save_settings
27792818 _apply_country_rules " $code "
2819+ _ensure_default_drop
27802820 }
27812821 fi
27822822 else
@@ -2795,9 +2835,11 @@ show_geoblock_menu() {
27952835 save_settings
27962836 _remove_country_rules " $rm_code "
27972837 rm -f " ${GEOBLOCK_CACHE_DIR} /${rm_code} .zone"
2838+ # Remove default-DROP if no countries left in whitelist mode
2839+ [ -z " $BLOCKLIST_COUNTRIES " ] && _remove_default_drop
27982840 log_success " Removed ${rm_code^^} — rules and cache cleared"
27992841 else
2800- log_info " Country '${rm_code} ' is not in the blocklist "
2842+ log_info " Country '${rm_code} ' is not in the list "
28012843 fi
28022844 else
28032845 log_error " Invalid country code (use 2-letter ISO code)"
@@ -2812,11 +2854,24 @@ show_geoblock_menu() {
28122854 _remove_country_rules " $code "
28132855 rm -f " ${GEOBLOCK_CACHE_DIR} /${code} .zone"
28142856 done
2857+ _remove_default_drop
28152858 BLOCKLIST_COUNTRIES=" "
28162859 save_settings
28172860 log_success " All geo-blocks cleared"
28182861 press_any_key
28192862 ;;
2863+ 4)
2864+ # Remove all current rules before switching mode
2865+ geoblock_remove_all
2866+ _remove_default_drop
2867+ # Toggle mode
2868+ [ " $GEOBLOCK_MODE " = " blacklist" ] && GEOBLOCK_MODE=" whitelist" || GEOBLOCK_MODE=" blacklist"
2869+ save_settings
2870+ # Reapply rules in new mode
2871+ [ -n " $BLOCKLIST_COUNTRIES " ] && geoblock_reapply_all
2872+ log_success " Geo-blocking mode: ${GEOBLOCK_MODE} "
2873+ press_any_key
2874+ ;;
28202875 0|" " ) return ;;
28212876 * ) ;;
28222877 esac
@@ -3310,7 +3365,7 @@ load_tg_settings() {
33103365 case "$key" in
33113366 PROXY_PORT|PROXY_DOMAIN|PROXY_METRICS_PORT|PROXY_CONCURRENCY|\
33123367 PROXY_CPUS|PROXY_MEMORY|CUSTOM_IP|PROXY_PROTOCOL|MASKING_ENABLED|MASKING_HOST|MASKING_PORT|\
3313- AD_TAG|BLOCKLIST_COUNTRIES|AUTO_UPDATE_ENABLED|\
3368+ AD_TAG|GEOBLOCK_MODE| BLOCKLIST_COUNTRIES|AUTO_UPDATE_ENABLED|\
33143369 TELEGRAM_ENABLED|TELEGRAM_BOT_TOKEN|TELEGRAM_CHAT_ID|\
33153370 TELEGRAM_INTERVAL|TELEGRAM_SERVER_LABEL|TELEGRAM_ALERTS_ENABLED)
33163371 printf -v "$key" '%s' "$val" ;;
@@ -4592,6 +4647,8 @@ cli_main() {
45924647 fi
45934648 check_root
45944649 if validate_port " $new_port " ; then
4650+ # Remove geoblock rules on old port before changing
4651+ [ -n " $BLOCKLIST_COUNTRIES " ] && { geoblock_remove_all; _remove_default_drop; }
45954652 PROXY_PORT=" $new_port "
45964653 save_settings
45974654 log_success " Port changed to ${new_port} "
@@ -4723,6 +4780,7 @@ cli_main() {
47234780 [ -z " $BLOCKLIST_COUNTRIES " ] && BLOCKLIST_COUNTRIES=" $code " || BLOCKLIST_COUNTRIES=" ${BLOCKLIST_COUNTRIES} ,${code} "
47244781 save_settings
47254782 _apply_country_rules " $code "
4783+ _ensure_default_drop
47264784 }
47274785 fi
47284786 else
@@ -4738,6 +4796,7 @@ cli_main() {
47384796 save_settings
47394797 _remove_country_rules " $code "
47404798 rm -f " ${GEOBLOCK_CACHE_DIR} /${code} .zone"
4799+ [ -z " $BLOCKLIST_COUNTRIES " ] && _remove_default_drop
47414800 log_success " Removed ${code^^} — rules and cache cleared"
47424801 else
47434802 log_info " Country '${code^^} ' is not blocked"
@@ -4755,6 +4814,7 @@ cli_main() {
47554814 _remove_country_rules " $code "
47564815 rm -f " ${GEOBLOCK_CACHE_DIR} /${code} .zone"
47574816 done
4817+ _remove_default_drop
47584818 BLOCKLIST_COUNTRIES=" "
47594819 save_settings
47604820 log_success " All geo-blocks cleared"
@@ -5406,6 +5466,8 @@ show_settings_menu() {
54065466 echo -en " ${BOLD} New port:${NC} "
54075467 local p; read -r p
54085468 if validate_port " $p " ; then
5469+ # Remove geoblock rules on old port before changing
5470+ [ -n " $BLOCKLIST_COUNTRIES " ] && { geoblock_remove_all; _remove_default_drop; }
54095471 PROXY_PORT=" $p "
54105472 save_settings
54115473 log_success " Port set to ${p} "
0 commit comments