source: trunk/uribl/URIdb.pm@ 88

Last change on this file since 88 was 88, checked in by Kris Deugau, 4 days ago

/trunk/uribl

Fill out tinydns export branch for completeness, although using anything
other than rbldnsd or similar for DNSBL data is more than a bit looney.

  • Property svn:keywords set to Date Rev Author Id
File size: 7.2 KB
Line 
1# URIdb
2# Functions for interacting with the URI database
3##
4# $Id: URIdb.pm 88 2025-09-11 22:03:48Z kdeugau $
5# Copyright 2010,2025 Kris Deugau <kdeugau@deepnet.cx>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19##
20
21package URIdb;
22
23use strict;
24use warnings;
25use Exporter;
26use DBI;
27use NetAddr::IP;
28
29use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
30
31$VERSION = 2.0;
32@ISA = qw(Exporter);
33@EXPORT_OK = qw( $dbh );
34
35@EXPORT = qw( $dbh );
36
37%EXPORT_TAGS = ( ALL => [qw(
38 )]
39 );
40
41## "constants"
42
43# 8 bits available
44# 128 is per-IP shitlist
45# 2 is IP hitlist
46# 1 not available so we don't $self->shoot(foot)
47our %status = (
48 0 => "Don't list",
49 2 => "Black",
50 4 => "Grey",
51 8 => "Abused URL shortener/redirector"
52);
53
54# variables
55our $dbh;
56
57our $err;
58our $errstr;
59
60# basic object subs
61sub new {
62 my $this = shift;
63 my $class = ref($this) || $this;
64 my %args = @_;
65
66 # Prepopulate a basic config. Note some of these *will* cause errors if left unset.
67 my %defconfig = (
68 dbhost => "localhost",
69 dbname => "dnsbl",
70 dbuser => "dnsbl",
71 dbpass => "spambgone",
72 );
73
74 my %siteconfig;
75 my $dbhost;
76 my $dbname;
77 my $dbuser;
78 my $dbpass;
79 if (defined($args{configfile})) {
80 if (-e $args{configfile} && -f $args{configfile}) {
81 my $ret = eval `cat $args{configfile}`;
82 unless ($ret) {
83 if ($@) { $errstr = "couldn't parse $args{configfile}: $@\n"; return; }
84 if (!defined($ret)) { $errstr = "couldn't load $args{configfile}: $!\n"; return; }
85 if (!$ret) { $errstr = "couldn't load $args{configfile}\n"; return; }
86 }
87 # crossload legacy variables, but prefer new %siteconfig values
88 $siteconfig{dbhost} = $dbhost if !$siteconfig{dbhost} && $dbhost;
89 $siteconfig{dbname} = $dbname if !$siteconfig{dbname} && $dbname;
90 $siteconfig{dbuser} = $dbuser if !$siteconfig{dbuser} && $dbuser;
91 $siteconfig{dbpass} = $dbpass if !$siteconfig{dbpass} && $dbpass;
92 }
93 }
94
95 # Assemble the object. Apply configuration hashes in order of precedence.
96 my $self = {
97 # Hardcoded defaults
98 %defconfig,
99 # Default config file OR caller-specified one, loaded above
100 %siteconfig,
101 # Caller-specified arguments
102 %args
103 };
104 bless $self, $class;
105
106 return $self;
107}
108
109sub DESTROY {
110 my $self = shift;
111 $self->dbclose() if $dbh;
112}
113
114# JIC someone wants to close the db but not finish the script
115sub dbclose {
116 $dbh->rollback;
117 $dbh->disconnect;
118}
119
120## specific object subs:
121
122sub connect {
123 my $self = shift;
124 ## want to NOT autocommit everything, it's unlikely we'll step on our own toes but...
125 $dbh = DBI->connect("DBI:Pg:host=$self->{dbhost};dbname=$self->{dbname}", $self->{dbuser}, $self->{dbpass}, {
126 AutoCommit => 0,
127 PrintError => 1
128 })
129 or die "database inaccessible: ".$DBI::errstr;
130 my $sth = $dbh->prepare("SELECT key,value FROM misc");
131 $sth->execute;
132 while (my ($key,$value) = $sth->fetchrow_array) {
133 $self->{misc}{$key} = $value;
134 }
135 $self->{misc}{blzone} = 'uribl.company.com' if !$self->{misc}{blzone};
136 return $dbh;
137}
138
139
140# report a URI to the db
141# increments a hit counter iff the reported URI exists, otherwise it adds it
142# requires the uri.
143# can accept the listing level and a comment
144sub report {
145 my $self = shift;
146 my $uri = shift;
147 my $list = shift || 2;
148 my $comment = shift || '';
149
150 my $sth;
151 my $rows = 0;
152 $sth = $dbh->prepare("SELECT count FROM urilist WHERE uri=?");
153 $sth->execute($uri) or die "eep? ".$dbh->errstr."\n";
154 $rows = $sth->rows;
155 if ($rows == 0) {
156 $sth = $dbh->prepare("INSERT INTO urilist (uri,list,comment) VALUES (?,?,?)");
157 $sth->execute($uri,$list,$comment) or die "couldn't add $uri: ".$dbh->errstr."\n";
158 } elsif ($rows == 1) {
159 $sth = $dbh->prepare("UPDATE urilist SET count=count+1 WHERE uri=?");
160 $sth->execute($uri) or die "couldn't update listing for $uri: ".$dbh->errstr."\n";
161 } else {
162 die "db corrupt: found $rows matches on $uri\n";
163 }
164 $dbh->commit;
165 return $rows;
166} # end report()
167
168
169sub exists {
170 my $self = shift;
171 my $checkme = shift;
172
173 my $sth = $dbh->prepare("SELECT count(*) FROM urilist WHERE uri=?");
174 $sth->execute($checkme);
175 my ($count) = $sth->fetchrow_array;
176 return $count;
177}
178
179
180# Write the data straight to a DNS server's files.
181# Takes a server type and open filehandle.
182sub export {
183 my $self = shift;
184 my $target = shift;
185 my $blfh = shift;
186
187 my $sth;
188
189##fixme: should probably rejig this key to point to a FQDN rather than a "something that will get published under .dnsbl"
190 my $blzone = ($self->{misc}{blzone} ? $self->{misc}{blzone} : 'uri').".dnsbl";
191 my $bladmin = ($self->{misc}{bladmin} ? $self->{misc}{bladmin} : 'systems.company.com');
192 my $blttl = ($self->{misc}{ttl} ? $self->{misc}{ttl} : '900');
193##fixme: should probably add some configuration strings for the nameserver value
194
195 if ($target eq 'rbldnsd') {
196 print $blfh "\$SOA 900 $blzone.dnsbl $bladmin 0 1200 600 600 900\n".
197 "\$NS 3600 127.0.0.1\n".
198 "\$TTL $blttl\n";
199 print $blfh ":127.0.0.2:Domain found in reported missed-spam, no legitimate root or www content\n";
200 $sth = $dbh->prepare("SELECT uri FROM urilist WHERE list=2");
201 $sth->execute;
202 while (my ($uri) = $sth->fetchrow_array) {
203 print $blfh ".$uri\n";
204 }
205 print $blfh ":127.0.0.4:Domain seen repeatedly in reported missed-spam, some legitimate root or www content\n";
206 $sth = $dbh->prepare("SELECT uri FROM urilist WHERE list=4");
207 $sth->execute;
208 while (my ($uri) = $sth->fetchrow_array) {
209 print $blfh ".$uri\n";
210 }
211 print $blfh ":127.0.0.8:Abused URL-shortener or redirector domain\n";
212 $sth = $dbh->prepare("SELECT uri FROM urilist WHERE list=8");
213 $sth->execute;
214 while (my ($uri) = $sth->fetchrow_array) {
215 print $blfh ".$uri\n";
216 }
217 } elsif ($target eq 'tinydns') {
218 print $blfh "Z$blzone.dnsbl:$blzone.dnsbl:$bladmin::600:600:600:600\n";
219 print $blfh "\&$blzone.dnsbl:127.0.0.1::900\n";
220 $sth = $dbh->prepare("SELECT uri FROM urilist WHERE list=2");
221 $sth->execute;
222 while (my ($uri) = $sth->fetchrow_array) {
223 print $blfh "'$uri.$blzone:Domain found in reported missed-spam, no legitimate root or www content:900::\n".
224 "+$uri.$blzone:127.0.0.2:900::\n";
225 }
226 $sth = $dbh->prepare("SELECT uri FROM urilist WHERE list=4");
227 $sth->execute;
228 while (my ($uri) = $sth->fetchrow_array) {
229 print $blfh "'$uri.$blzone:Domain seen repeatedly in reported missed-spam, some legitimate root or www content:900::\n".
230 "+$uri.$blzone:127.0.0.4:900::\n";
231 }
232 $sth = $dbh->prepare("SELECT uri FROM urilist WHERE list=8");
233 $sth->execute;
234 while (my ($uri) = $sth->fetchrow_array) {
235 print $blfh "'$uri.$blzone:Abused URL-shortener or redirector domain:900::\n".
236 "+$uri.$blzone:127.0.0.8:900::\n";
237 }
238 } elsif ($target eq 'bind') {
239 } else {
240 }
241 return;
242} # end export()
243
244
245# make Perl happy
2461;
Note: See TracBrowser for help on using the repository browser.