Problem/Motivation
The ban module enables you to store single IP-addresses, from which any access of the website will be prevented.
In some cases spammers uses IP-ranges from where they spam contact forms.
Steps to reproduce
NA
Proposed resolution
So it would be nice to have a comfortable opportunity to block IP-ranges or if the usage of wildcards would be supported.
Remaining tasks
Review
User interface changes
Ban range

API changes
NA
Data model changes
NA
Release notes snippet
Original post
The ban module enables you to store single IP-addresses, from which any access of the website will be prevented.
In some cases spammers uses IP-ranges from where they spam contact forms. So it would be nice to have a comfortable opportunity to block IP-ranges or if the usage of wildcards would be supported.
| Comment | File | Size | Author |
|---|---|---|---|
| #54 | interdiff_2972332_52-54.txt | 334 bytes | ankithashetty |
| #54 | 2972332-54.patch | 16.32 KB | ankithashetty |
| #52 | interdiff_2972332_51-52.txt | 591 bytes | ankithashetty |
| #52 | 2972332-52.patch | 16.32 KB | ankithashetty |
| #51 | 2972332-51.patch | 16.32 KB | _utsavsharma |
Issue fork ban-2972332
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
goodboy commentedI created advban module as core Ban module fork and add some features: range ban, expire ban. I planned add whitelist and other features also. These changes required the addition of new columns to the table. My features may be included to Drupal's 9 Ban module.
Comment #4
goodboy commentedAdd range IP ban
Comment #5
goodboy commentedTry apply the same patch with absolute paths
Comment #6
longwaveComment #8
goodboy commentedFix error: wrong table name
Comment #9
longwaveComment #11
goodboy commentedFix some errors and change by coding standarts. But don''t understand about unknown ip_end column which added on ban.install
Comment #12
goodboy commentedComment #13
goodboy commentedChange db_add_field to construction like $injected_database->schema()->addField
Comment #14
goodboy commentedComment #15
goodboy commentedAdd default arguments to function definitions
Comment #16
goodboy commentedComment #17
goodboy commentedComment #18
dawehnerInteresting idea. To be honest it feels like ban module could totally actually live outside of core. What are your thoughts about that?
How about naming it ip_range_end, so its a bit more obvious what this field is about?
I'm wondering whether for better BC there should be additional methods instead. We could then also have some state variable to store whether we need any range checking at all. This way runtime level checks could stay basically the same for existing sites.
Why do you have to check for the existence of this field? This would be quite a slow query on every request
Comment #19
goodboy commentedDawehner, thank you for review. I made Advanced ban (advban)
1. Ok, I will change the field name
2. I will fix the query code, after testing
I use second argument for ban functions as array in my advban module. So no need create new functions. For example, I use expire time for banning
3. This code need for passing drupal.org test only. It will be removed on productive.
I will do create new patch, thank you
Comment #20
andypostit could be oneliner
+ $schema = \Drupal::database()->schema();
it looks strange that code expects that field could be missing
This code needs comments cos not clear how conditions grouped and how that affects performance because no index on new field and `>=` for strings could have visible effect
Comment #21
goodboy commentedandypost, thank you for review
1. I just copy the code from /core/system/system.install. I will fix it
2. Without this table existing checking test do not passed. I created topic which referenced to this one. I will try again to pass the test after removing this code.
3. Range IP stored long values to the ip and ip_end fields. I'm looking for such intervals for which the address is inside, for start IP and for end IP. I will add comments.
Comment #22
goodboy commentedComment #23
goodboy commentedremove $this->connection->schema()->fieldExists('ban_ip', 'ip_end')
Comment #26
goodboy commentedComment #28
goodboy commentedComment #29
goodboy commentedCreate patch from 8.7-dev version
Comment #30
goodboy commentedIt looks like when you run process that will update the database and add a new field, it checks the IP address, which uses a new field that has not yet been created. If this is a feature of the Ban module, the test can be considered as passed.
Or, as was previously done and criticized, add a check for the existence of a new field.
Comment #31
goodboy commentedAdd new field exists checking
Comment #32
goodboy commentedComment #33
goodboy commentedDelete new column exists check and add try/catch block
Comment #34
volegerThis can be removed as it not used.
Code style issue. Remove 1 space at the beginning of the line.
Code style issue. Add a new line after the last method.
Code style issues. Fix indentation needed.
Make those lines more readable, i.e.
Comment #35
goodboy commented@voleger, thanks for your review. I've added test for IP range also.
Comment #36
goodboy commentedFix testing error.
Comment #38
goodboy commentedFix path
Comment #39
goodboy commentedComment #43
andypostThere's contrib implementation https://www.drupal.org/project/restrict_ip
Comment #49
smustgrave commentedThis issue is being reviewed by the kind folks in Slack, #needs-review-queue-initiative. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge request as a guide.
Tagged for needs reroll
Think this would be a nice feature to still have!
Comment #50
_utsavsharma commentedRerolled patch for 10.1.x.
Comment #51
_utsavsharma commentedFixed CCF for #51.
Comment #52
ankithashettyFixed the phpunit test errors in #51, thanks!
Comment #53
smustgrave commentedfunction ban_update_8700() {This needs to be updated for D10.
Comment #54
ankithashettyThanks for the review @smustgrave!🙌🏼
Updated the patch as requested.
Thanks!
Comment #55
smustgrave commentedThanks for the quick turnaround
On Drupal 10.1. with a standard install
Tested the update hook does pass.
Uploading a screenshot of what the UI now looks like (added IS template while I was at it)
Running the tests without the fix I get
Changes look good
Comment #56
longwaveAs well as the below comments I also wonder that if instead of arbitrary start and end IPs, we should support CIDR ranges, e.g. 192.168.0.0/16 to ban all of 192.168.0.0 to 192.168.255.255. That would be easier to store and parse.
Wondering if this works as intended in all cases, given that the
ipandip_range_endcolumns are defined as strings, but here we seem to be doing a numeric comparison.What are the possible options? We need to document this.
ban -> unban
Also, what happens with overlapping ranges?
None of the UI changes in this patch (such as these lines above) have test coverage.
Comment #58
quietone commentedThe Ban Module was approved for removal in #1570102: [Policy] Deprecate Ban module.
This remains Postponed. The status is set according to two policies. The Remove a core extension and move it to a contributed project and the Extensions approved for removal policies.
The deprecation work is in #3482198: [meta] Tasks to deprecate the Ban module and the removal work in #3488827: [meta] Tasks to remove Ban module.
Ban will be moved to a contributed project after the Drupal 12.x branch is open.
Comment #60
mstrelan commentedMoved to contrib queue
Comment #61
anybodyI think it should just allow CIDR notation and use standards, instead of inventing an own notation?
Maybe for adding IPs a textarea could be used?
Comment #62
anybodyAnd let's please use a MR instead of patches.
Comment #63
anybodyUsing IpUtils here like in #3392147: Add an allowed IP list to the Ban module should help a lot providing IP block support and unify things. Let's do that!
If someone needs more, that should be done in a follow-up imho.
Comment #66
grevil commentedAll done, please review!
I feel like this is the better approach even though, we pull the entire database table column in memory.
Comment #67
anybodyThanks @grevil, yes I also think this is a good, standardized and consistent solution now!
Some final points I'd like to add are:
Maybe someone else here can also review or proceed?
Comment #68
grevil commentedComment #69
grevil commented@vloeger, thanks for the suggestions, I think the validator should be a simple helper class. I don't think we need to decorate it or inject it at any point. It should simply hold two simple static validation methods, that's it. But of course I am open for discussion 🙂.
Comment #70
anybodyDue to the (even if small) fundamental changes and possible performance implications, I'd like to wait for feedback by @mstrelan.
Comment #71
mstrelan commentedI'd need to have a better look, but I'm not at all comfortable with this query with no condition or limit:
$banned = $this->connection->query('SELECT [ip] FROM {ban_ip}')?->fetchCol();Particular in light of #3153262: Add pagination to banned IPs view
I think there are some tricks to query this directly. Postgres has built in support for this but Mysql doesn't. I think you can convert the cidr to an int and store that, maybe in a separate column, and then you can do a BETWEEN query.
You might want to see if @berdir has some feedback on this
Comment #72
grevil commented@mstrelan thanks for the feedback! Yea that might be a problem if we pull 7000+ ip strings in PHP memory... we are currently not really in need of this feature, so if anyone wants to finish it, feel free to!
@berdir any thoughts on this?
Comment #73
berdirFetching all IP's is definitely a no-go.
I also saw stuff about this in advban, but didn't investigate closely, but even that then adds a second query to every request with complex conditions.
As mentioned in the advban issue, I'm personally also not too interested in having support for this and think it should definitely be optional to keep overhead of this minimal as this is something that runs on every request, even page cache hits. One option for that would be putting this feature into a separate, optional module.
Vague thoughts to consider:
* Store them in a separate table, easier to load all then.
* Cache them, possibly keyed by the first part (I've also thought about this for regular IP lookups, but that might be more complexity than it's worth)
* Implement something like what advban does, but as mentioned, that's then multiple queries per request.
* backend specific implementations if postgresql can do this natively.
Comment #74
anybodyThanks @berdir I agree with that. A further question is, if CIDR syntax is enough or if we need a broader "range" functionality or just a textarea for multiple entries?
I'd vote for the textarea and CIDR only. While the textarea should go into the main module, CIDR should be a submodule IMHO.
The module should allow that.
Comment #75
berdirA single textarea for CIDR ranges sounds sensible. That also fits pretty well with what I know from Upsun: https://fixed.docs.upsun.com/environments/http-access-control.html#filte... (not sure we should support the allow/ban feature, that sounds complicated in combination with single IP's, I think just blocking is fine)
Still wondering how to most efficiently get that information into the super-early ban middleware. We don't want to read config and inject the ConfigFactory there, see my auto_unban issue. it could be put directly in a service parameter in a ServiceProvider class, like language module does. But every change would require a pretty expensive container rebuild. A fast chained bootstrap cache might be acceptable, reading config only on a miss, with a service closure.
Comment #76
anybodyBased on the feedback I'd say we should postpone this. Next step would be to move the range / CIDR functionality into a submodule to make it optional and describe the possible negative performance impacts, I'd say?
Comment #77
anybodyBased on the valid reasons given above I'll close this won't fix. For anyone who needs a quick solution and is aware of the performance implications, please use https://www.drupal.org/project/advban
I'll add some information to the module page.
Comment #78
anybodyDone! @goodboy I also linked your modules on the module page now, would be great if you could do a comparison vice-versa. Blocking IP-ranges is and will be a USP of your module now and in the future :)