# HTTP DDoS protection

**URL:** <https://swi-prolog.discourse.group/t/http-ddos-protection/9509>\
**Category:** Discussion\
**Tags:** http\
**Created:** [February 5, 2026, 7:24am UTC](https://swi-prolog.discourse.group/t/http-ddos-protection/9509 "2026-02-05T07:24:42Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![drspro](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/drspro/32/3509_2.png) [@drspro](https://swi-prolog.discourse.group/u/drspro)\
**Post date:** [February 5, 2026, 7:24am UTC](https://swi-prolog.discourse.group/t/http-ddos-protection/9509/1 "2026-02-05T07:24:42Z")

</div>

maybe we can also make some efficient code to protect against DDOS attacks.

will it be faster if the ip-adres is asserted as number instead of atom, to measure the time between http-requests of 1 specific ip adres.

If nowadays you watch the logs of web-servers there are many automised http requests, in many cases they issue more than 10 requests in 1 second.

so if more than X requests between Y time, then permanently block that ip-adres, and that before the session cookie is created

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [February 5, 2026, 9:28am UTC](https://swi-prolog.discourse.group/t/http-ddos-protection/9509/2 "2026-02-05T09:28:25Z")

</div>

> [@drspro](#):
>
> will it be faster if the ip-adres is asserted as number instead of atom

In SWI-Prolog ip addresses are ip(A,B,C,D) or ip(A, B, C, D, E, F, G, H) (IPv6) terms. The fun thing is that I used ip(A,B,C,D) because in very old days SWI-Prolog integers were (I think) 28 bits, so they could not hold an IP address 🙂

I use something similar to DDoS protection in SWISH code for establishing web sockets. This sometimes fails, causing many retry requests. The idea is to add a penalty on every request and have a decay function if no request came in for some time. So, for each IP address you need a score (number) and last time stamp.

You can implement this in the HTTP server main thread. This thread merely calls tcp\_accept/3 and then passes the accepted socket to a pool. You can also implement it in the dispatching code. Next, I think you roughly have these options  
(suggests more if I missed some):

- Use a Prolog term, e.g., library(assoc). You can use that when implemented in the server main thread or you could run it inside an _engine_.
- Use a SWI-Prolog _dict_ as above. Probably faster and cheaper if there are up to about 1,000 distinct IP addresses in your pool.
- Use a SWI-Prolog _trie_.
- Use the dynamic database.

It is a little hard to say how these three would compare. My intuition says that the _trie_ is the most likely winner, both time and space wise.

---

<div class="post-metadata">

**Author:** ![drspro](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/drspro/32/3509_2.png) [@drspro](https://swi-prolog.discourse.group/u/drspro)\
**Post date:** [February 5, 2026, 10:56am UTC](https://swi-prolog.discourse.group/t/http-ddos-protection/9509/3 "2026-02-05T10:56:09Z")

</div>

that is very extensive information thankyou. i didnt know about the Ipv6 format , i will use it. my brains can handle at most / max the dynamic predicates stuff. indeed a score is needed and a time stamp. I made a very simple code here.

```prolog
:- dynamic ip_behaviour/7.

judge_interval( Time_difference , do_block_ip ) :- Time_difference < 0.3 , ! .
judge_interval( _Time_difference , do_allow_ip ) :- ! .

allow_ip_request( ip( Nu1, Nu2, Nu3, Nu4 ) , do_block_ip ):-
% it was already asserted as to block it 
 ip_behaviour( Nu1, Nu2, Nu3, Nu4 , _Last_time , _Time_difference , Judgement ) , 
 Judgement == do_block_ip , ! .

allow_ip_request( ip( Nu1, Nu2, Nu3, Nu4 ) , Judgement ):-
 retract( ip_behaviour( Nu1, Nu2, Nu3, Nu4 , Previous_time , _Previous_interval , _Allow_or_block ) ) ,
 get_time( Now ), Xinterval is Now - Previous_time , 
 judge_interval( Time_difference , Judgement , ) , 
 assert( ip_behaviour( Nu1, Nu2, Nu3, Nu4 , Now , Xinterval , Judgement ) ) .

allow_ip_request( ip( Nu1, Nu2, Nu3, Nu4 ) , do_allow_ip ):- !,
 % the ip is new / has never been encountered yet , so assert it
 get_time( Now ), 
 assert( ip_behaviour( Nu1, Nu2, Nu3, Nu4 , Now , 5 , do_allow_ip ) ) .

```

---

<div class="post-metadata">

**Author:** ![mgondan1](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/mgondan1/32/803_2.png) [@mgondan1](https://swi-prolog.discourse.group/u/mgondan1)\
**Post date:** [February 5, 2026, 9:19pm UTC](https://swi-prolog.discourse.group/t/http-ddos-protection/9509/4 "2026-02-05T21:19:06Z")

</div>

> [@jan](#):
>
> very old days SWI-Prolog integers were (I think) 28 bits, so they could not hold an IP address 🙂

Out of curiosity, were the remaining four bits “type bits”?

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [February 6, 2026, 8:05am UTC](https://swi-prolog.discourse.group/t/http-ddos-protection/9509/5 "2026-02-06T08:05:10Z")

</div>

> [@mgondan1](#):
>
> Out of curiosity, were the remaining four bits “type bits”?

SWI-Prolog always had 3 type bits. So, maybe it was 29 … The initial versions had no GC. GC uses another 2 bits. Not sure when sockets were added. I do remember that using an integer was no option because they could not represent the 32 bits IP address.

Maybe the git repo goes back far enough 🙂
