1 -- Regano database DoS protection module
3 -- Uses PostgreSQL extensions.
5 -- Regano is a domain registration system for OpenNIC TLDs written in
6 -- Perl. This file is part of Regano.
8 -- Regano may be distributed under the same terms as Perl itself. Of
9 -- particular importance, note that while regano is distributed in the
10 -- hope that it will be useful, there is NO WARRANTY OF ANY KIND
11 -- WHATSOEVER WHETHER EXPLICIT OR IMPLIED.
13 -- The type definitions in db_types.sql must already be installed.
14 -- The function definitions in db_functions.sql must already be installed.
15 -- The main API definitions in db_api.sql must already be installed.
16 -- The configuration in db_config.sql must be loaded for these to actually work.
18 -- Currently blocked clients
19 CREATE TABLE IF NOT EXISTS regano.antiskid_block (
20 client inet PRIMARY KEY,
21 blocked timestamp with time zone
22 NOT NULL DEFAULT CURRENT_TIMESTAMP
23 ) WITH (fillfactor = 90);
24 CREATE INDEX ON regano.antiskid_block (blocked);
26 -- Tally of expensive operations
27 CREATE TABLE IF NOT EXISTS regano.antiskid_tally (
29 points integer NOT NULL
31 tallied timestamp with time zone
32 NOT NULL DEFAULT CURRENT_TIMESTAMP,
33 PRIMARY KEY(client, tallied, points)
35 CREATE INDEX ON regano.antiskid_tally (tallied);
37 ALTER TABLE regano.antiskid_block OWNER TO regano;
38 ALTER TABLE regano.antiskid_tally OWNER TO regano;
40 -- Check if a client may perform an expensive operation.
41 CREATE OR REPLACE FUNCTION regano_api.antiskid_check
45 block_expire CONSTANT interval NOT NULL
46 := (regano.config_get('antiskid/block')).interval;
47 points_expire CONSTANT interval NOT NULL
48 := (regano.config_get('antiskid/tally')).interval;
49 points_threshold CONSTANT integer NOT NULL
50 := (regano.config_get('antiskid/tally')).number;
52 add_points integer NOT NULL
53 := (regano.config_get('antiskid/weight/'||op)).number;
54 current_points integer;
56 block regano.antiskid_block%ROWTYPE;
58 -- clean up blocked client list and check if client is blocked
60 FROM regano.antiskid_block
61 WHERE blocked < (now() - block_expire);
63 FROM regano.antiskid_block
66 IF block.blocked < (now() - (block_expire / 2)) THEN
67 UPDATE regano.antiskid_block
74 -- tally the new points and check if client should be blocked
75 INSERT INTO regano.antiskid_tally (client, points)
76 VALUES (addr, add_points);
77 SELECT SUM(points) INTO STRICT current_points
78 FROM regano.antiskid_tally
79 WHERE client = addr AND tallied >= (now() - points_expire);
80 IF current_points > points_threshold THEN
81 INSERT INTO regano.antiskid_block (client) VALUES (addr);
85 -- clean up point tallies and return success
87 FROM regano.antiskid_tally
88 WHERE tallied < (now() - points_expire);
91 $$ LANGUAGE plpgsql VOLATILE STRICT SECURITY DEFINER;
92 ALTER FUNCTION regano_api.antiskid_check (text, inet)
95 -- Check for valid session from non-blocked client
96 CREATE OR REPLACE FUNCTION regano_api.antiskid_session_check
100 block_expire CONSTANT interval NOT NULL
101 := (regano.config_get('antiskid/block')).interval;
104 FROM regano.antiskid_block
105 WHERE client = addr AND blocked > (now() - block_expire);
109 RETURN regano_api.session_check(id);
112 $$ LANGUAGE plpgsql VOLATILE STRICT SECURITY DEFINER;
113 ALTER FUNCTION regano_api.antiskid_session_check (uuid, inet)