├── LICENSE ├── README.md └── ipset-country /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ipset-country 2 | 3 | ## Block or allow countries using iptables, ipset and ipdeny.com 4 | 5 | --- 6 | 7 | _This used to be a [Gist](https://gist.github.com/mkorthof/3033ff64c4a5b4bd31336d422104d543) but was moved here instead_ 8 | _Please do not add Gist comments, but create an issue [here](https://github.com/mkorthof/ipset-country/issues)_ 9 | 10 | --- 11 | 12 | - [x] Also works with ipverse.com and other providers 13 | - [x] Supports RH, Debian with iptables and/or firewalld 14 | - [x] Both ipv4 and ipv6 are supported 15 | 16 | Installation 17 | ------------ 18 | 19 | 1) Setup firewall if you have not done so yet, **at least INPUT chain** is needed 20 | 2) Run this script from cron, e.g. /etc/cron.daily or a [systemd timer](https://www.freedesktop.org/software/systemd/man/systemd.timer.html) (see below) 21 | 3) To run on boot you can also add it to e.g. /etc/rc.local or systemd 22 | 4) Use argument "-f" to load unchanged zonefiles instead of skipping 23 | 24 | - To automatically setup a systemd service and daily timer run: `ipset-country -i` 25 | - To uninstall run:`ipset-country -u` 26 | 27 | Running this script will insert an iptables 'REJECT' or 'DROP' rule for ipset. 28 | Make sure you do not lock yourself out in case of issues on a remote system. 29 | 30 | In case of issues check the log file (/var/log/ipset-country.log) 31 | 32 | Configuration 33 | ------------- 34 | 35 | ***All options are set and explained in the script itself: [ipset-country](ipset-country)*** 36 | 37 | Optionally you can use a seperate config file located in the same directory as the script, "/etc" or "/usr/local/etc". Specify a custom location using `ipset-country -c /path/to/conf` 38 | 39 | The config file will overwrite any options set in script. To create a new conf file run: 40 | 41 | ``` bash 42 | sed -n '/# CONFIGURATION:/,/# END OF CONFIG/p' ipset-country > ipset-country.conf 43 | ``` 44 | 45 | --- 46 | 47 | **Distro:** 48 | 49 | If needed change OS using `DISTRO` setting. Default is "auto" which should be OK. 50 | 51 | Options are: 52 | - "auto", "debian" or "redhat" 53 | - "manual" 54 | - `confdir="/etc/iptables"` (example) 55 | - `rulesfile="${confdir}/myrules"` (example) 56 | 57 | --- 58 | 59 | **Countries:** 60 | 61 | Specify countries to block as `"ISOCODE,Name"` (same as ipdeny.com), multiple entries should be seperated by semicolon `;` 62 | 63 | Example: 64 | `COUNTRY="CN,China; US,United States; RU,Russia"` 65 | 66 | --- 67 | 68 | **Firewalls and options:** 69 | 70 | Iptables and ipset are used by default to create the chains, rules and ipsets. If firewalld frontend is enabled it will be used instead. 71 | 72 | - Blacklist: block specified Countries, set `MODE` to "reject" or "drop" 73 | - Whitelist: allow specified Countries and block all others, set `MODE` to "accept" 74 | 75 | Iptables: 76 | 77 | Set target to use when ip matches country: "accept", "drop" or "reject". Default is `MODE="reject"` 78 | 79 | FirewallD: 80 | 81 | Set this option to "1" to enable firewalld: `FIREWALLD=0` 82 | 83 | Set `FIREWALLD_MODE=0` to use the default Blacklist mode (uses 'drop' zone). Change to "1" for Whitelist ('public' zone). _See MODE above for more information_ 84 | 85 | * _NOTE:_ 86 | There are issues with firewalld on CentOS/RHEL 8 which can cause your firewall to break resulting in being locked out. Adding large ipsets apparently can take a VERY long time. To abort you need remote console access and run `pkill firewal-cmd; nft flush ruleset` 87 | 88 | --- 89 | 90 | **Block list providers:** 91 | 92 | Set URLs for ipv4 and/or ipv6 block files, you probably do not have to change these. 93 | To use [ipverse.net](http://ipverse.net) instead of [ipdeny.com](https://ipdeny.com) and for more details see [script](ipset-country) 94 | 95 | - `IPBLOCK_URL_V4="http://www.ipdeny.com/ipblocks/data/aggregated"` 96 | - `IPBLOCK_URL_V6="http://www.ipdeny.com/ipv6/ipaddresses/blocks"` 97 | 98 | --- 99 | 100 | **Logs:** 101 | In case you want to change file location set: `LOG="/var/log/ipset-country.log"` 102 | 103 | --- 104 | 105 | IPset 106 | ------ 107 | 108 | Useful ipset commands: 109 | 110 | - `ipset list` 111 | - `ipset test setname ` 112 | - `ipset flush` 113 | - `ipset destroy` 114 | 115 | Changes 116 | ------- 117 | 118 | - [20220227] fixed iptables-legacy paths (pr #16 by mainboarder) 119 | - [20201212] added config file option, systemd install (pr #14 by srulikuk) 120 | - [20201108] added flush option, fix restore=0 (pr #13 by srulikuk) 121 | - [20200927] fixed restore + logips bug (pr #10 by G4bbix) 122 | - [20200605] added Blacklist/Whitelist mode (#3) 123 | - [20200129] added option to DROP instead of REJECT (#1) 124 | - [20191116] added ipverse support, md5check option 125 | - [20190905] tested on debian 10 and centos 7 126 | - [20190905] blocking multiple countries should work 127 | - [20190905] it will check if INPUT chain exists in iptables 128 | - [20190905] cleaned it up a bit 129 | - [20190905] using firewalld is also supported now 130 | 131 | Alternatives 132 | ------------ 133 | 134 | Also available: [github.com/tokiclover/dotfiles/blob/master/bin/ips.bash](https://github.com/tokiclover/dotfiles/blob/master/bin/ips.bash) 135 | 136 | -------------------------------------------------------------------------------- /ipset-country: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ipset-country (v20200927) 3 | # ========================= 4 | 5 | # Block or allow countries using iptables, ipset and ipdeny.com 6 | # Also works with ipverse.com and other providers 7 | 8 | # INSTALLATION: 9 | # ------------- 10 | 11 | # - Setup firewall if you have not done so yet, at least INPUT chain is needed 12 | # - Run this script from cron, e.g. /etc/cron.daily 13 | # - To run on boot you can also add it to e.g. /etc/rc.local or systemd 14 | # - Use argument "force" to load unchanged zonefiles instead of skipping 15 | 16 | # NOTE: This script will insert an iptables REJECT or DROP rule for ipset, 17 | # make sure you do not lock yourself out in case of issues on a remote system 18 | 19 | # CONFIGURATION: 20 | # -------------- 21 | 22 | # OS: "auto", "manual", "debian", "suse" or "redhat" (default is auto) 23 | # Manual example: confdir="/etc/iptables", rulesfile="${confdir}/myrules" 24 | 25 | DISTRO="auto" 26 | 27 | # Specify countries to block as 'ISOCODE,Name' (same as ipdeny.com) 28 | # Multiple entries should be seperated by semicolon 29 | # Example: "CN,China; US,United States; RU,Russia" 30 | 31 | COUNTRY="CN,China; RU,Russia" 32 | 33 | # ---[ FIREWALLS AND OPTIONS ]------------------------------------------------- 34 | # Iptables and ipset are used by default to create the chains, rules and ipsets 35 | # Firewalld can be enabled to use firewalld-cmd frontend 36 | # UFW is an unsupported and untested frontend, but might work 37 | # Nftables can be used with firewalld, default is to use iptables-legacy 38 | # Blacklist: block specified Countries, set MODE to "reject" or "drop" 39 | # Whitelist: allow specified Countries and block all others, set "accept" 40 | 41 | # Iptables 42 | MODE="reject" # Set target to use when ip matches country [accept|drop|reject] 43 | RESTORE=0 # Run iptables-restore first, before adding rules [0/1] 44 | LOGIPS=1 # Create logips chain to log matches [0/1] 45 | 46 | # FirewallD 47 | FIREWALLD=0 # Use firewalld instead [0/1] 48 | FIREWALLD_MODE=0 # Set 0 for default Blacklist (drop), or 1 to Whitelist [0/1] 49 | FIREWALLD_RH8=0 # Enable firewalld on CentOS/RHEL 8, at your own risk [0/1] 50 | 51 | # UFW 52 | UFW=0 # Set to 1 to use iptables besides ufw, at your own risk [0/1] 53 | 54 | # ---[ BLOCK LIST PROVIDERS ]--------------------------------------------------- 55 | # IPdeny: "http://www.ipdeny.com/ipblocks/data/aggregated" (aggregated ipv4) 56 | # "http://www.ipdeny.com/ipv6/ipaddresses/blocks" (ipv6) 57 | # "http://www.ipdeny.com/ipblocks/data/countries" (full ipv4) 58 | # IPverse: "http://ipverse.net/ipblocks/data/countries" 59 | # Others: should work if they offer (iso) country zonefiles with CIDR's 60 | # Notes: - the "aggregated" zonefiles are smaller in size 61 | # - ipdeny has no md5sums for aggregated ipv6 zonefiles 62 | # - ipverse does not offer md5sums at all (this autosets MD5CHECK=0) 63 | # comment ipdeny lines and uncomment line below to use ipverse instead: 64 | # IPBLOCK_URL="http://ipverse.net/ipblocks/data/countries" 65 | 66 | IPBLOCK_URL_V4="http://www.ipdeny.com/ipblocks/data/aggregated" 67 | IPBLOCK_URL_V6="http://www.ipdeny.com/ipv6/ipaddresses/blocks" 68 | IPV4=1 # Use ipv4, ipv6 or both 69 | IPV6=0 # For ipv6 also set IPBLOCK_URL_V6 [0/1] 70 | MD5CHECK=1 # Check zonefile md5sums [0/1] 71 | FORCE=0 # Run even if zonefile is unchanged [0/1] 72 | # same as running './ipset-country force' 73 | FLUSH=0 # Flush ipset before adding zonefile [0/1] 74 | # this will take care of removed ranges 75 | 76 | # Log to file, or to disable logging use: "/dev/null 2>&1" 77 | LOG="/var/log/ipset-country.log" 78 | # Level, see below and man syslog [0-7] 79 | # ( 0=emerg 1=alert crit=2 3=err 4=warning 5=notice 6=info 7=debug ) 80 | LOGLVL=6 81 | 82 | # END OF CONFIG 83 | # ------------- 84 | 85 | # Commands and script variables 86 | # ipset cmds : ipset list | test setname | flush | destroy 87 | # rc ipset : ips_a = ipset add, ips_c = create, ips_f = protocol family 88 | # rc iptables : ipt_i = insert rule, ipt_t = rule target, ipt_n = new chain 89 | # ipt_l = log rule, ipt_r = restore 90 | # executables : ipt = ipt{,6}tables, iptrestore = ip{,6}tables-restore 91 | # iptsave = ip{,6}tables-save 92 | 93 | scriptname="$( basename "$0" )" 94 | basefile="$(basename -s '.sh' "$0")" 95 | 96 | # arg '-c' config file 97 | SAVE_IFS="$IFS" 98 | IFS='|'; c=0 99 | for i in "$@"; do 100 | if printf -- "%s" "$i" | grep -Eq -- "\-c"; then 101 | c=1 102 | continue 103 | else 104 | if [ "$c" -eq 1 ]; then 105 | if printf -- "%s" "$i" | grep -Eq -- "\-"; then 106 | echo "Error: config file not specfied, try \"$scriptname -h\"" 107 | exit 1 108 | fi 109 | scriptconf="$i" 110 | if [ ! -s "$scriptconf" ]; then 111 | echo "Error: invalid config file \"$scriptconf\" specified" 112 | exit 1 113 | fi 114 | break 115 | fi 116 | fi 117 | done 118 | IFS="$SAVE_IFS" 119 | # if scriptconf is empty, check for {/usr/local,}/etc/ipset-country.conf and in same dir as script 120 | if [ -z "$scriptconf" ]; then 121 | sc="$(dirname "$0")/${basefile}.conf" 122 | for i in "/usr/local/etc/ipset-country.conf" "/etc/ipset-country.conf" "$sc"; do 123 | if [ -e "$i" ]; then 124 | scriptconf="$i" 125 | break 126 | fi 127 | done 128 | fi 129 | unset i 130 | # make sure we dont source ourselves 131 | if [ "$scriptconf" = "$0" ]; then 132 | echo "Error: invalid config file \"$scriptconf\" specified" 133 | exit 1 134 | fi 135 | # source scriptconf if its non empty, else exit 136 | if [ -n "$scriptconf" ] && [ -s "$scriptconf" ]; then 137 | # shellcheck source=/usr/local/etc/ipset-country.conf 138 | . "$scriptconf" || { echo "Error: could not load $scriptconf"; exit 1; } 139 | fi 140 | 141 | iptr_run=0 142 | ip6r_run=0 143 | logips_run=0 144 | logip6_run=0 145 | 146 | nl=' 147 | ' 148 | SAVE_LOG="$LOG" 149 | 150 | func_msg() { 151 | msg="$*"; eol="$nl"; tee=0 152 | if echo "$msg" | grep -q '^m:'; then 153 | # shellcheck disable=SC2048 154 | for i in $*; do 155 | # set output "mode" 156 | case $i in 157 | m:logfile) LOG="$SAVE_LOG" ;; 158 | m:stdout) tee=0; LOG="/dev/stdout"; ;; 159 | m:tee) tee=1 ;; 160 | m:nonl) eol=" " ;; 161 | esac 162 | done 163 | msg="$( echo "$msg" | sed -E 's/m:(nonl|stdout|tee) //g' )" 164 | fi 165 | if [ "$tee" -eq 1 ]; then 166 | printf "%s %s%s" "$( date +%F\ %T )" "$msg" "$eol" | tee -a "$LOG" 167 | else 168 | printf "%s %s%s" "$( date +%F\ %T )" "$msg" "$eol" >> $LOG 169 | fi 170 | } 171 | 172 | func_dist_auto() { 173 | if [ -s /etc/os-release ]; then 174 | if grep -iq "debian\\|ubuntu" /etc/os-release; then DISTRO="debian" 175 | elif grep -iq "centos\\|fedora\\|rhel" /etc/os-release; then DISTRO="redhat" 176 | elif grep -iq "suse" /etc/os-release; then DISTRO="suse" 177 | fi 178 | else 179 | [ -s /etc/debian_version ] && DISTRO="debian" 180 | [ -s /etc/redhat-release ] && DISTRO="redhat" 181 | [ -s /etc/SuSE-release ] && DISTRO="suse" 182 | fi 183 | } 184 | 185 | # set iptables and other vars 186 | func_vars() { 187 | confdir="/etc" 188 | if [ "$proto" = "ipv6" ]; then 189 | ipt="ip6" 190 | ips_f="inet6" 191 | rj="icmp6-port-unreachable" 192 | case $DISTRO in 193 | debian) 194 | rulesfile="/etc/ip6tables.up.rules" 195 | [ -d "/etc/iptables" ] && confdir="/etc/iptables" 196 | [ -f "${confdir}/rules.v6" ] && rulesfile="${confdir}/rules.v6" 197 | ;; 198 | redhat|suse) 199 | confdir="/etc/sysconfig" 200 | rulesfile="${confdir}/ip6tables" 201 | ;; 202 | esac 203 | else 204 | ipt="ip" 205 | ips_f="inet" 206 | rj="icmp-port-unreachable" 207 | case $DISTRO in 208 | debian) 209 | rulesfile="/etc/iptables.up.rules" 210 | [ -d "/etc/iptables" ] && confdir="/etc/iptables" 211 | [ -f "${confdir}/rules.v4" ] && rulesfile="${confdir}/rules.v4" 212 | ;; 213 | redhat|suse) 214 | confdir="/etc/sysconfig" 215 | rulesfile="${confdir}/iptables" 216 | ;; 217 | esac 218 | fi 219 | if [ -x "/usr/sbin/${ipt}tables-legacy" ]; then 220 | iptables="/usr/sbin/${ipt}tables-legacy" 221 | iptrestore="/usr/sbin/${ipt}tables-legacy-restore" 222 | iptsave="/usr/sbin/${ipt}tables-legacy-save" 223 | else 224 | iptables="/sbin/${ipt}tables" 225 | iptrestore="/sbin/${ipt}tables-restore" 226 | iptsave="/sbin/${ipt}tables-save" 227 | fi 228 | if [ "$DISTRO" = "suse" ] ; then 229 | iptables="/usr${iptables}" 230 | iptrestore="/usr${iptrestore}" 231 | iptsave="/usr${iptsave}" 232 | fi 233 | if [ "$FIREWALLD" -eq 1 ]; then 234 | frontend="firewalld" 235 | if [ "$DISTRO" = "redhat" ] && [ "$FIREWALLD_RH8" -ne 1 ]; then 236 | if grep -Eiq "red hat enterprise linux 8.0|centos linux 8" /etc/os-release; then 237 | echo 238 | echo "WARNING: There are issues with firewalld on CentOS/RHEL 8 which can cause" 239 | echo " your firewall to break resulting in being locked out." 240 | echo " Adding large ipsets apparently can takes a VERY long time. To abort you need" 241 | echo " remote console access and run 'pkill firewal-cmd; nft flush ruleset'" 242 | echo " Set FIREWALLD_RH8=1 to disable this message" 243 | echo 244 | printf "Press any key to quit or 'Y' then [ENTER] to continue " 245 | read -r a 246 | if ! echo "$a" | grep -iq y; then exit 1; fi 247 | FIREWALLD_RH8=1 248 | func_msg m:stdout "continuing..." 249 | fi 250 | fi 251 | else 252 | frontend="${ipt}tables" 253 | if [ "$RESTORE" -eq 1 ] && [ ! -f "$rulesfile" ]; then 254 | func_msg m:stdout "could not find iptables rules file \"${rulesfile}\"" 255 | exit 1 256 | fi 257 | fi 258 | } 259 | 260 | # download zonefile and get md5sum if enabled 261 | func_zf() { 262 | zonefile="${ctyiso}.zone" 263 | if echo "$url" | grep -iq "ipdeny\.com"; then 264 | if echo "$url" | grep -q "aggregated"; then 265 | zonefile="${ctyiso}-aggregated.zone" 266 | if [ "$proto" = "ipv6" ]; then 267 | MD5CHECK=0 268 | fi 269 | fi 270 | fi 271 | zoneurl="$zonefile" 272 | if echo "$url" | grep -iq "ipverse\.net"; then 273 | MD5CHECK=0 274 | if [ "$proto" = "ipv6" ]; then 275 | zoneurl="${ctyiso}-ipv6.zone" 276 | fi 277 | fi 278 | $getfile "/tmp/${proto}-${zonefile}.$$" "${url}/${zoneurl}" 279 | # check downloaded zonefile against MD5SUM 280 | if [ "$MD5CHECK" -eq 1 ]; then 281 | md5src="$( $getfile - "$url/MD5SUM" | grep "$zonefile" | cut -d" " -f 1 )" 282 | fi 283 | # check if zonefile is the same as current 284 | md5chk="$( md5sum "/tmp/${proto}-${zonefile}.$$" | cut -d" " -f 1 )" 285 | if [ -f "${confdir}/${proto}-${zonefile}" ]; then 286 | md5cur="$( md5sum "${confdir}/${proto}-${zonefile}" 2>/dev/null | cut -d" " -f 1 )" 287 | if [ -z "$md5cur" ] || [ "$md5cur" = "" ]; then 288 | zf="NOK: md5" 289 | fi 290 | fi 291 | if [ "$md5cur" != "$md5chk" ]; then 292 | mv "/tmp/${proto}-${zonefile}.$$" "${confdir}/${proto}-${zonefile}" && \ 293 | zf="OK" || zf="NOK" 294 | else 295 | if [ "$FORCE" -ne 1 ]; then zf="SKIP"; else zf="FORCE"; fi 296 | fi 297 | func_msg "zonefile: get \"${proto}-${zonefile}\" - $zf" 298 | } 299 | 300 | # restore iptables, once 301 | func_ipt_res() { 302 | if { [ "$proto" = "ipv4" ] && [ "$iptr_run" -ne 1 ]; } || 303 | { [ "$proto" = "ipv6" ] && [ "$ip6r_run" -ne 1 ]; } 304 | then 305 | $iptrestore < "$rulesfile" && ipt_r="OK" || ipt_r="NOK" 306 | func_msg "$frontend: restore - $ipt_r" 307 | [ "$proto" = "ipv4" ] && iptr_run=1 308 | [ "$proto" = "ipv6" ] && ip6r_run=1 309 | fi 310 | } 311 | 312 | # check if logips chain and rules already exist, else create them - once 313 | func_ipt_log() { 314 | ipt_q=0 315 | if { [ "$proto" = "ipv4" ] && [ "$logips_run" -ne 1 ]; } || 316 | { [ "$proto" = "ipv6" ] && [ "$logip6_run" -ne 1 ]; } 317 | then 318 | if ! $iptsave | grep -q "LOGIPS"; then 319 | $iptables -N LOGIPS && ipt_n="OK" || ipt_n="NOK" 320 | else 321 | ipt_n="already exists" 322 | fi 323 | if ! $iptsave | grep -q "LOGIPS.*LOG"; then 324 | $iptables -A LOGIPS -m limit --limit 10/min -j LOG --log-prefix "IPS: " --log-level $LOGLVL && \ 325 | ipt_l="OK" || ipt_l="NOK" 326 | else 327 | ipt_l="already exists" 328 | fi 329 | case "$MODE" in 330 | accept) 331 | if ! $iptsave | grep -q "LOGIPS.*REJECT"; then 332 | if ! $iptsave | grep -q "LOGIPS.*DROP"; then 333 | if ! $iptsave | grep -q "LOGIPS.*ACCEPT"; then 334 | $iptables -A LOGIPS -j ACCEPT && ipt_t="OK" || ipt_t="NOK" 335 | else ipt_t="ACCEPT already exists"; fi 336 | else ipt_t="DROP already exists, remove it first"; ipt_q=1; fi 337 | else ipt_t="REJECT already exists, remove it first"; ipt_q=1; fi 338 | ;; 339 | drop) 340 | if ! $iptsave | grep -q "LOGIPS.*REJECT"; then 341 | if ! $iptsave | grep -q "LOGIPS.*DROP"; then 342 | $iptables -A LOGIPS -j DROP && ipt_t="OK" || ipt_t="NOK" 343 | else ipt_t="DROP already exists"; fi 344 | else ipt_t="REJECT already exists, remove it first"; ipt_q=1; fi 345 | ;; 346 | reject|*) 347 | if ! $iptsave | grep -q "LOGIPS.*DROP"; then 348 | if ! $iptsave | grep -q "LOGIPS.*REJECT"; then 349 | $iptables -A LOGIPS -j REJECT --reject-with "$rj" && ipt_t="OK" || ipt_t="NOK" 350 | else ipt_t="REJECT already exists"; fi 351 | else ipt_t="DROP already exists, remove it first"; ipt_q=1; fi 352 | ;; 353 | esac 354 | func_msg "$frontend: create log chain - $ipt_n" 355 | func_msg "$frontend: append log rule - $ipt_l" 356 | func_msg "$frontend: append $MODE rule - $ipt_t" 357 | [ "$ipt_q" -ne 0 ] && { func_msg m:stdout "exiting..."; exit 1; } 358 | [ "$proto" = "ipv4" ] && logips_run=1 359 | [ "$proto" = "ipv6" ] && logip6_run=1 360 | fi 361 | } 362 | 363 | # add ipset deny rule at last line in input chain or line number 1 364 | func_ipt_deny() { 365 | rulenum=$(( $(${iptables} -S INPUT 2>/dev/null|wc -l) - 1 )) || rulenum=1 366 | # alternative method, slower: 367 | # rulenum="$(( $(${iptables} -L INPUT --line-numbers | tail -1 | awk '{print $1}') - 1 ))" 368 | [ "$rulenum" -eq 0 ] && rulenum=1 369 | if $iptsave | grep -q "match-set.*${proto}-${ctyname}.*LOGIPS"; then 370 | ipt_i="already exists" 371 | else 372 | $iptables -I INPUT "$rulenum" -p tcp -m set --match-set "${proto}-${ctyname}" src -j LOGIPS && \ 373 | ipt_i="OK" || ipt_i="NOK" 374 | fi 375 | # if logips chain does not exist - because logips=0 or previous cmds failed - insert ipset block rule 376 | if ! $iptsave | grep -q "\\-A LOGIPS" || test $LOGIPS -eq 0; then 377 | if [ "$MODE" = "reject" ]; then 378 | # also check if ipset rule doesnt exist 379 | if $iptsave | grep -q "match-set.*${proto}-${ctyname}.*REJECT"; then 380 | ipt_i="already exists" 381 | else 382 | $iptables -I INPUT "$rulenum" -p tcp -m set --match-set "${proto}-${ctyname}" src -j REJECT --reject-with "$rj" && \ 383 | ipt_i="OK" || ipt_i="NOK" 384 | fi 385 | elif [ "$MODE" = "drop" ]; then 386 | if $iptsave | grep -q "match-set.*${proto}-${ctyname}.*DROP"; then 387 | ipt_i="already exists" 388 | else 389 | $iptables -I INPUT "$rulenum" -p tcp -m set --match-set "${proto}-${ctyname}" src -j DROP && \ 390 | ipt_i="OK" || ipt_i="NOK" 391 | fi 392 | fi 393 | fi 394 | func_msg "$frontend: insert ipset deny rule - $ipt_i" 395 | } 396 | 397 | # add ipset allow rule 398 | func_ipt_allow() { 399 | rulenum=1 400 | if $iptsave | grep -q "match-set.*${proto}-${ctyname}.*LOGIPS"; then 401 | ipt_i="already exists" 402 | else 403 | $iptables -I INPUT "$rulenum" -p tcp -m set --match-set "${proto}-${ctyname}" src -j LOGIPS && \ 404 | ipt_i="OK" || ipt_i="NOK" 405 | fi 406 | # if logips chain does not exist - because logips=0 or previous cmds failed - insert ipset block rule 407 | if ! $iptsave | grep -q "\\-A LOGIPS" || test $LOGIPS -eq 0; then 408 | if $iptsave | grep -q "match-set.*${proto}-${ctyname}.*ACCEPT"; then 409 | ipt_i="already exists" 410 | else 411 | $iptables -I INPUT "$rulenum" -p tcp -m set --match-set "${proto}-${ctyname}" src -j ACCEPT && \ 412 | ipt_i="OK" || ipt_i="NOK" 413 | fi 414 | fi 415 | func_msg "$frontend: insert ipset allow rule - $ipt_i" 416 | } 417 | 418 | # create ipset using type hash 419 | func_ips_create() { 420 | { ipset list -terse "${proto}-${ctyname}" >/dev/null 2>&1 || ipset create "${proto}-${ctyname}" hash:net family ${ips_f}; } && \ 421 | ips_c="OK" || ips_c="NOK" 422 | func_msg "ipset: create set \"${proto}-$ctyname\" - $ips_c" 423 | } 424 | 425 | # add blocks to ipset 426 | func_ips_add() { 427 | [ "$FLUSH" -eq 1 ] && ipset flush "${proto}-${ctyname}" 428 | i=0; while read -r cidr; do 429 | ipset -A -exist -quiet "${proto}-${ctyname}" "$cidr" && i=$((i+1)) || echo "NOK: \"${proto}-${ctyname}\" - $i - $cidr" 430 | done < "${confdir}/${proto}-${zonefile}" >/dev/null 2>&1 && ips_a="OK" || ips_a="NOK" 431 | [ "$i" -eq 0 ] && ips_a="NOK" 432 | func_msg "ipset: add \"${proto}-${zonefile}\" to \"${proto}-${ctyname}\" - $ips_a - $i entries" 433 | } 434 | 435 | func_firewalld_ips() { 436 | if ! $firewallcmd --get-ipsets | grep -q "${proto}-${ctyname}"; then 437 | func_msg m:nonl "$frontend: new ipset \"${proto}-${ctyname}\" -" 438 | $firewallcmd --permanent --new-ipset="${proto}-${ctyname}" --type=hash:net --option=family="${ips_f}" >>"$LOG" 2>&1 439 | fi 440 | func_msg m:nonl "$frontend: add to ipset -" 441 | $firewallcmd --permanent --ipset="${proto}-${ctyname}" --add-entries-from-file="${confdir}/${proto}-${zonefile}" >>"$LOG" 2>&1 && { \ 442 | i="$( ipset -terse list "${proto}-${ctyname}" | awk 'END { print $NF }' )" 443 | func_msg "ipset: add \"${proto}-${zonefile}\" to \"${proto}-${ctyname}\" - $i entries" 444 | } 445 | } 446 | 447 | func_firewalld_drop() { 448 | if ! $firewallcmd --zone=drop --list-sources | grep -q "${proto}-${ctyname}"; then 449 | func_msg m:nonl m:tee "$frontend: add source to drop zone -" 450 | { $firewallcmd --permanent --zone=drop --add-source="ipset:${proto}-${ctyname}" && echo; } >>"$LOG" 2>&1 451 | fi 452 | } 453 | 454 | func_firewalld_public() { 455 | if ! $firewallcmd --zone=public --list-sources | grep -q "${proto}-${ctyname}"; then 456 | func_msg m:nonl m:tee "$frontend: add source to public zone -" 457 | { $firewallcmd --permanent --zone=public --add-source="ipset:${proto}-${ctyname}" && echo; } >>"$LOG" 2>&1 458 | fi 459 | } 460 | 461 | # arg "-i" installs systemd service 462 | if printf -- "%s" "$*" | grep -Eq -- "\-i"; then 463 | if [ ! -d /run/systemd/system ]; then 464 | echo "ERROR: systemd not found" 465 | exit 1 466 | fi 467 | if [ -e /lib/systemd/system/ipset-country.service ]; then 468 | echo "ERROR: systemd service already exists" 469 | exit 1 470 | fi 471 | cat <<-_EOF_ > /lib/systemd/system/ipset-country.service 472 | [Unit] 473 | Description=ipset-country 474 | 475 | [Service] 476 | Type=oneshot 477 | ExecStart=$(dirname "$(readlink -f "$0")")/$scriptname 478 | StandardError=file:/var/log/ipset-country.err 479 | RemainAfterExit=true 480 | 481 | [Install] 482 | WantedBy=multi-user.target 483 | _EOF_ 484 | cat <<-_EOF_ > /lib/systemd/system/ipset-country.timer 485 | Description=ipset-country daily timer 486 | 487 | [Timer] 488 | OnBootSec=2min 489 | OnCalendar=daily 490 | 491 | [Install] 492 | WantedBy=timers.target 493 | _EOF_ 494 | # shellcheck disable=SC2015 495 | systemctl daemon-reload && \ 496 | systemctl enable --now ipset-country.timer || \ 497 | { echo "ERROR: could not start systemd timer"; exit 1; } 498 | echo "Systemd service and timer 'ipset-country' installed" 499 | exit 500 | fi 501 | 502 | # arg "-u" uninstalls systemd service 503 | if printf -- "%s" "$*" | grep -Eq -- "\-u"; then 504 | systemctl stop ipset-country 505 | systemctl stop ipset-country.timer 506 | systemctl disable ipset-country 507 | systemctl disable ipset-country.timer 508 | rm /lib/systemd/system/ipset-country.service 509 | rm /lib/systemd/system/ipset-country.timer 510 | systemctl daemon-reload 511 | systemctl reset-failed 512 | exit 513 | fi 514 | 515 | # preflight checks 516 | 517 | if printf -- "%s" "$*" | grep -Eq -- "\-h|help"; then 518 | echo"" 519 | echo "./$scriptname [-c |-i|-u|-f]" 520 | echo 521 | echo " -c specify config file" 522 | echo " -i install systemd service and timer" 523 | echo " -u uninstall from systemd" 524 | echo " -f force loading unchanged zonefiles" 525 | echo 526 | echo "See comments in script and README.md for details" 527 | echo 528 | exit 0 529 | fi 530 | if [ "$( id -u )" -ne 0 ]; then 531 | echo "Script \"$scriptname\" needs root to run" 532 | exit 1 533 | fi 534 | if [ "$UFW" -ne 1 ]; then 535 | # shellcheck disable=SC2230 536 | if which ufw >/dev/null 2>&1; then 537 | if ufw status | grep -q "Status: active"; then 538 | echo "UFW is not supported, disable it first (or set UFW=1)" 539 | exit 1 540 | fi 541 | fi 542 | fi 543 | if printf -- "%s" "$*" | grep -Eiq -- "\-f|force"; then 544 | FORCE=1 545 | fi 546 | if [ ! -w "$( dirname "$LOG" )" ]; then 547 | echo "Log \"$LOG\" not writable, using \"/tmp/${basefile}.log\" instead" 548 | LOG="/tmp/${basefile}.log" 549 | fi 550 | if printf -- "%s" "$*" | grep -Eiq -- "debug"; then 551 | LOG=/dev/stdout 552 | fi 553 | 554 | [ "$DISTRO" = "auto" ] && func_dist_auto 555 | func_vars 556 | 557 | if [ "$FIREWALLD" -eq 1 ]; then 558 | # shellcheck disable=SC2230 559 | firewallcmd="$( which firewall-cmd 2>/dev/null )" 560 | test -x "$firewallcmd" && fwd_c="OK" || fwd_c="NOK - NOT FOUND" 561 | func_msg "$frontend: firewall-cmd - $fwd_c" 562 | if [ "$fwd_c" != "OK" ]; then 563 | func_msg m:stdout "try disabling option \"set FIREWALLD=0\", exiting..." 564 | exit 1 565 | fi 566 | else 567 | if ! echo "$MODE" | grep -Eq "accept|drop|reject" ; then 568 | echo "invalid MODE setting" 569 | exit 1 570 | fi 571 | test -x "$iptables" && ipt_c="OK" || ipt_c="NOK - NOT FOUND" 572 | $iptables -n -L INPUT >/dev/null 2>&1 && ipt_p="OK" || ipt_p="OK" 573 | test -d "$confdir" && ipt_d="OK" || ipt_d="NOK - NOT FOUND" 574 | if [ "$ipt_c" != "OK" ] || [ "$ipt_p" != "OK" ];then 575 | func_msg m:tee "$frontend: $iptables ${ipt_c}, input chain: $ipt_p" 576 | fi 577 | if [ "$ipt_d" != "OK" ];then 578 | func_msg m:tee "$frontend: confdir $confdir - $ipt_d" 579 | fi 580 | if [ "$ipt_c" != "OK" ] || [ "$ipt_p" != "OK" ] || [ "$ipt_d" != "OK" ]; then 581 | func_msg m:tee "exiting..." 582 | exit 1 583 | fi 584 | fi 585 | 586 | # shellcheck disable=SC2230 587 | ipset="$( which ipset 2>/dev/null )" 588 | test -x "$ipset" && ips_e="OK" || ips_e="NOK - NOT FOUND" 589 | if [ "$ips_e" != "OK" ]; then 590 | func_msg m:tee "ipset: $ips_e, exiting..." 591 | exit 1 592 | fi 593 | 594 | # shellcheck disable=SC2230 595 | { getfile=$( which wget 2>/dev/null ) && getfile="$getfile -q -O"; } 596 | if [ -z "$getfile" ]; then 597 | func_msg m:stdout "curl or wget not found, exiting..." 598 | exit 1 599 | fi 600 | # shellcheck disable=SC2230 601 | which md5sum >/dev/null 2>&1 || \ 602 | { func_msg m:stdout "md5sum not found, exiting..."; exit 1; } 603 | 604 | # main loop: handle country here 605 | func_block_ip() { 606 | SAVE_IFS="$IFS" 607 | IFS=";" 608 | for cty in $COUNTRY; do 609 | cty="$( echo "$cty" | tr '[:upper:]' '[:lower:]' )" 610 | ctyiso="$( echo "$cty" | cut -d',' -f 1 | sed -r -e 's/(^ +| +$)//g' )" 611 | ctyname="$( echo "$cty" | cut -d',' -f 2 | sed -r -e 's/(^ +| +$)//g' -e 's/ /_/g' )" 612 | if [ "$ctyname" != "" ]; then 613 | IFS="$SAVE_IFS" 614 | for url in $1; do 615 | # if its an ipv6 zonefile url: change protocol 616 | if echo "$url" | grep -q "ipv6"; then 617 | proto="ipv6" 618 | fi 619 | func_vars 620 | func_zf 621 | if [ "$MD5CHECK" -eq 0 ] || [ "$md5src" = "$md5chk" ]; then 622 | if [ "$zf" != "SKIP" ]; then 623 | if [ "$FIREWALLD" -eq 1 ]; then 624 | func_firewalld_ips 625 | if [ "$FIREWALLD_MODE" -eq 1 ]; then 626 | # blacklist 627 | func_firewalld_public 628 | else 629 | # whitelist 630 | func_firewalld_drop 631 | fi 632 | else 633 | func_ips_create 634 | if [ "$RESTORE" -eq 1 ]; then 635 | func_ipt_res 636 | fi 637 | if [ "$LOGIPS" -eq 1 ] && [ "$FIREWALLD" -ne 1 ]; then 638 | func_ipt_log 639 | fi 640 | func_ips_add 641 | if [ "$MODE" = "accept" ]; then 642 | # whitelist 643 | func_ipt_allow 644 | else 645 | # blacklist 646 | func_ipt_deny 647 | fi 648 | fi 649 | fi 650 | else 651 | func_msg "zonefile: md5 \"${proto}-${zonefile}\" mismatch\"" 652 | fi 653 | done 654 | else 655 | func_msg m:stdout "incorrect country setting\"" 656 | fi 657 | if [ -f "/tmp/${proto}-${zonefile}.$$" ]; then 658 | rm "/tmp/${proto}-${zonefile}.$$" 659 | fi 660 | done 661 | } 662 | 663 | if [ "$IPV4" -eq 1 ]; then 664 | proto="ipv4" 665 | if [ -z "$IPBLOCK_URL_V4" ]; then 666 | IPBLOCK_URL_V4="$IPBLOCK_URL" 667 | fi 668 | func_block_ip "$IPBLOCK_URL_V4" 669 | fi 670 | 671 | # ipv6 uses '/sbin/ip6tables' 672 | if [ "$IPV6" -eq 1 ]; then 673 | proto="ipv6" 674 | if [ -z "$IPBLOCK_URL_V6" ]; then 675 | IPBLOCK_URL_V6="$IPBLOCK_URL" 676 | fi 677 | if [ -z "$IPBLOCK_URL_V6" ] && [ -z "$IPBLOCK_URL" ]; then 678 | IPBLOCK_URL_V6="$IPBLOCK_URL_V4" 679 | fi 680 | func_block_ip "$IPBLOCK_URL_V6" 681 | fi 682 | 683 | if [ "$FIREWALLD" -eq 1 ]; then 684 | func_msg m:nonl m:stdout "firewalld: reload -" 685 | $firewallcmd --reload >>"$LOG" 2>&1 686 | fi 687 | func_msg m:stdout "ipset-country: done" 688 | IFS="$SAVE_IFS" 689 | --------------------------------------------------------------------------------