source: trunk/uribl/URIdb.pm@ 101

Last change on this file since 101 was 101, checked in by Kris Deugau, 2 days ago

/trunk/uribl

File off most of the rough edges on configuration from the misc table; all
keys now have defaults in the object, overrides happen correctly, and all
keys are filled in to the appropriate places in the output rather than
hardcoding things.

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