#!/usr/bin/perl -w # Ad Banner server for ad-free webbing. # Original code Waider 1997 or so. # Revamped July 2000 when I learned a little more about Perl, but it's # still disgusting. It's not multithreaded or anything. # # December 2001: Mozilla no longer groks XBMs, or at least not with # the headers I'm putting out. So I'm switching to PNGs, as I'd # planned on doing at some point anyway. # # While I was at it, I cleaned up the code a little. Not much, though. # # April 20, 2003: Conditionalised printing of request details # 06/08/2003: fortune is no longer packaged on redhat, alas. use Socket; use GD; use strict; my $port = $ARGV[0] || 3129; my $debug = 0; $|=1; my ($name, $aliases, $proto) = getprotobyname('tcp'); ($name, $aliases, $port) = getservbyname($port, 'tcp') unless $port =~ /^\d+$/; my $this = sockaddr_in( $port, "\0\0\0\0"); select(NS); $| = 1; select(STDOUT); socket(S, &PF_INET, &SOCK_STREAM, $proto) || die "socket: $!"; bind(S, $this) || die "bind: $!"; listen(S, 5) || die "connect: $!"; select(S); $| = 1; select(STDOUT); for (;;) { accept(NS,S) || die $!; my ($port, $inetaddr ) = sockaddr_in( getpeername( NS )); my ( $rin, $rout, $win, $wout, $ein, $eout, $nbytes, $buf, $line, $nfound ); my $chunk = ""; while( 1 ) { $rin=$rout=$win=$wout=$ein=$eout=''; vec( $rin, fileno( NS ), 1) = 1; vec( $win, fileno( NS ), 1) = 1; $ein=$rin|$win; $nfound=select( $rout=$rin, $wout=$win, $eout=$ein, 0 ); if ( $nfound ) { if ( vec( $rout, fileno( NS ), 1 )) { $nbytes=sysread( NS, $buf, 1024 ); last if !defined( $nbytes ); last if $nbytes<1; } } $chunk .= $buf if defined $buf; if ( length( $chunk ) && $nbytes ) { $line = $chunk; $line=~ s/\r\n/\n/g; last if ( $line =~ /\n\n/ ); } undef $buf; $nbytes = 0; } #print "Request: $chunk\n" if defined( $chunk ); # Parse request # GET http://ad.uk.doubleclick.net/ad/theregister.co.uk/regindex;area=regindex;pos=1;sz=468x60;tile=1;abr=!ie4;abr=!ie5;ord=12345? HTTP/1.0 # Referer: http://www.theregister.co.uk/ # Proxy-Connection: Keep-Alive # User-Agent: Mozilla/4.74 [en] (X11; U; Linux 2.2.17pre13 i686) # Pragma: no-cache # Host: ad.uk.doubleclick.net # Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png # Accept-Encoding: gzip # Accept-Language: en # Accept-Charset: iso-8859-1,*,utf-8 my ( $meth, $req ) = $chunk =~ m{^(GET|HEAD) (.*) HTTP/}mi; my ( $accept ) = $chunk =~ m{^Accept: (.*)$}mi; $meth ||= "GET"; $accept ||= "image/*"; $req ||= ""; my ( $w, $h ) = $req =~ m{sz=(\d+)x(\d+)}; my ( $im ); # Fun! my $phrase = "NO ADVERTS, THANKS"; if ( -x "/usr/games/fortune" ) { if ( open( YOW, "/usr/games/fortune -s|" )) { # short fortunes only $phrase = join( '', ); close( YOW ); } } $phrase =~ s/\s+/ /g; # convert all whitespace to spaces $phrase =~ s/\s+$//; # and lose trailing whitespace. my @phrase; # Defaults derived from size of phrase # 468 x 60 is actually the 'standard' banner # This if (!defined( $w )) { $w = length( $phrase ) * 6 + 6; if ( $w > 468 ) { $w = 468; # which turns out to fit nicely } } my $pl = int(( $w - 6 ) / 6 ); if ( length( $phrase ) > $pl ) { while ( $phrase ) { my $ph = substr( $phrase, 0, $pl ); $ph =~ s/ [^ ]+$// if length( $ph ) == $pl; if ( length( $ph )) { push @phrase, $ph; } else { push @phrase, "Can't wrap the wittiness..."; $phrase = ""; } $phrase = substr( $phrase, length( $ph )); $phrase =~ s/^\s+//; } } else { push @phrase, $phrase; } $h = 12 * scalar( @phrase ) + 5 if !defined( $h ); $im = new GD::Image( $w, $h ); # Now let's put something in it: my $white = $im->colorAllocate( 255, 255, 255 ); my $black = $im->colorAllocate( 0, 0, 0 ); $im->rectangle( 0, 0, $w - 1, $h - 1, $white ); $im->rectangle( 1, 1, $w - 2, $h - 2, $black ); my $y = 1; for $phrase ( @phrase ) { $im->string( gdSmallFont, 3, $y, $phrase, $black ); $y += 12; } # Convert to a PNG for schlepping off to the client my $image = $im->png; # Parsed version, or, my regexps are working. if ( $debug ) { print "Method: $meth\n"; print "Requesting: $req\n"; print "Size: $w x $h\n" if ( defined ( $h ) && defined( $w )); print "Accepting: $accept\n"; } if ( $chunk =~ /HEAD/ ) { $buf = "HTTP/1.0 200 OK\r\n"; $buf .= "Date: Wed, 24 Feb 1999 12:27:10 GMT\r\n"; $buf .= "Content-Type: image/png\r\n"; $buf .= "\r\n"; } else { $buf = "HTTP/1.0 200 OK\r\n"; $buf .= "Content-Length: " . length( $image ) . "\r\n"; $buf .= "Content-Type: image/png\r\n\r\n"; $buf .= $image; } $nbytes = length( $buf ); binmode NS; while( $nbytes>0 ) { my $written = syswrite( NS, $buf, $nbytes ); last if !defined( $written ); last if $written < 0; $nbytes -= $written; $buf = substr($buf, $written); } if ( vec( $eout, fileno( NS ), 1 )) { print "Error.\n" ; next; } # Close connection when client shuts down + kill child process close(NS); #print "Connection closed.\n"; }