Initial checkin for move to Git (no prior version history available). master
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Tue, 22 Jan 2013 16:17:48 +0000 (17:17 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Tue, 22 Jan 2013 16:17:48 +0000 (17:17 +0100)
access_list.pl [new file with mode: 0644]
mbd.pl [new file with mode: 0644]
nets.pl [new file with mode: 0644]

diff --git a/access_list.pl b/access_list.pl
new file mode 100644 (file)
index 0000000..26ef9ff
--- /dev/null
@@ -0,0 +1,106 @@
+
+package Config;
+
+our @access_list = (
+       # half-life - untested (packet dump only)
+       {
+               ports => [ 27015 ],
+               sizes => [ 16 ]
+       },
+
+       # cs 1.6 - verified
+       # (funker muligens for _alle_ source-spill inkl. hl2/cs:s)
+       {
+               ports => [ 4242, "26900..26905", "27015..27020" ],
+               sizes => [ 25 ]
+       },
+
+       # doom 3 - verified
+       {
+               ports => [ "27666..27673" ],
+               sizes => [ 14 ]
+       },
+
+       # quake 1 - verified
+       {
+               ports => [ 26000 ],
+               sizes => [ 12 ]
+       },
+
+       # q3a - tested with demo only
+       # rtcw: enemy territory - untested (packet dump only)
+       {
+               ports => [ "27960..27969" ],
+               sizes => [ 15 ]
+       },
+       
+       # bf2 - tested with demo only
+       # bf2142 reportedly uses same engine
+       {
+               ports => [ "29900..29950" ],
+               sizes => [ 8 ]
+       },
+
+       # bf1942 - unverified (packet dump only)
+       {
+               ports => [ "22000..22010" ],
+               sizes => [ 8 ]
+       },
+       
+       # quake 4 - tested with demo only, MUST select "internet"
+       {
+               ports => [ 27950, 28004 ],
+               sizes => [ 14 ]
+       },
+
+       # quake 2 - untested (packet dump only)
+       {
+               ports => [ 27910 ],
+               sizes => [ 11 ]
+       },
+
+       # warcraft 3 - untested (packet dump only)
+       {
+               ports => [ 6112 ],
+               sizes => [ 16 ]
+       },
+
+       # ut2003/ut2004 - untested (packet dump only)
+       {
+               ports => [ 10777 ],
+               sizes => [ 5 ]
+       },
+
+       # soldat - untested (packet dump only)
+       {
+               ports => [ 23073 ],
+               sizes => [ 8 ]
+       },
+
+       # starcraft - untested (packet dump only)
+       {
+               ports => [ 6111, 6112 ],
+               sizes => [ 8, 20 ]
+       },
+
+       # trackmania nations - untested (packet dump only)
+       {
+               ports => [ "2350..2370" ],
+               sizes => [ 42 ]
+       },
+
+       # company of heroes - untested (packet dump only)
+       {
+               ports => [ 9100 ],
+               sizes => [ 39 ]
+       },
+
+       # command & conquer 3 - untested (packet dump only, reported to have some kind
+       # of chat functionality)
+       {
+               ports => [ "8086..8093" ],
+               sizes => [ 476 ]
+       },
+
+       # unreal tournament, port 9777?
+)
diff --git a/mbd.pl b/mbd.pl
new file mode 100644 (file)
index 0000000..90ee4d6
--- /dev/null
+++ b/mbd.pl
@@ -0,0 +1,122 @@
+#! /usr/bin/perl
+use strict;
+use warnings;
+use Socket;
+use Net::CIDR;
+use Net::RawIP;
+require './access_list.pl';
+require './nets.pl';
+
+sub expand_range {
+       my $range = shift;
+
+       if ($range =~ /^(\d+)\.\.(\d+)$/) {
+               return $1..$2;
+       } else {
+               return $range;
+       }
+}
+
+sub match_ranges {
+       my ($elem, $ranges) = @_;
+       
+       for my $range (@$ranges) {
+               if ($range =~ /^(\d+)\.\.(\d+)$/) {
+                       return 1 if ($elem >= $1 && $elem <= $2);
+               } else {
+                       return 1 if ($elem == $range);
+               }
+       }
+
+       return 0;
+}
+
+sub fhbits {
+       my $bits = 0;
+       for my $fh (@_) {
+               vec($bits, fileno($fh), 1) = 1;
+       }
+       return $bits;
+}
+
+# Find what ports we need to listen on
+my %port_hash = ();
+for my $e (@Config::access_list) {
+       for my $r (@{$e->{'ports'}}) {
+               for my $p (expand_range($r)) {
+                       $port_hash{$p} = 1;
+               }
+       }
+}
+my @ports = sort { $a <=> $b } keys %port_hash;
+
+# Open a socket for each port
+my @socks = ();
+my $udp = getprotobyname("udp");
+for my $p (@ports) {
+       my $sock;
+       socket($sock, PF_INET, SOCK_DGRAM, $udp);
+       bind($sock, sockaddr_in($p, INADDR_ANY));
+       push @socks, $sock;
+}
+
+my $sendsock = Net::RawIP->new({udp => {}});
+
+print "Listening on " . scalar @ports . " ports.\n";
+
+# Main loop
+while (1) {
+       my $rin = fhbits(@socks);
+       my $rout;
+
+       my $nfound = select($rout=$rin, undef, undef, undef);
+       for my $sock (@socks) {
+               next unless (vec($rout, fileno($sock), 1) == 1);
+
+               my $data;
+               my $addr = recv($sock, $data, 8192, 0);   # jumbo broadcast! :-P
+               my ($sport, $saddr) = sockaddr_in($addr);
+               my ($dport, $daddr) = sockaddr_in(getsockname($sock));
+               my $size = length($data);
+
+               # We don't get the packet's destination address, but I guess this should do...
+               # Check against the ACL.
+               my $pass = 0;
+               for my $rule (@Config::access_list) {
+                       if (match_ranges($dport, $rule->{'ports'}) &&
+                           match_ranges($size, $rule->{'sizes'})) {
+                               $pass = 1;
+                       }
+               }
+
+               if (!$pass) {
+                       print "$dport, $size bytes => filtered\n";
+               }
+
+               next unless $pass;
+
+               for my $net (@Config::networks) {
+                       next if (Net::CIDR::cidrlookup(inet_ntoa($saddr), $net));
+
+                       my ($range) = Net::CIDR::cidr2range($net);
+                       $range =~ /-(.*?)$/;
+                       my $broadcast = $1;
+
+                       print inet_ntoa($saddr), ", $dport, $size bytes => $broadcast\n";
+
+                       $sendsock->set({
+                               ip => {
+                                       saddr => inet_ntoa($saddr),
+                                       daddr => $broadcast
+                               },
+                               udp => {
+                                       source => $sport,
+                                       dest => $dport,
+                                       data => $data
+                               }
+                       });
+                       $sendsock->send;
+               }
+       }
+}
+
diff --git a/nets.pl b/nets.pl
new file mode 100644 (file)
index 0000000..55bec01
--- /dev/null
+++ b/nets.pl
@@ -0,0 +1,9 @@
+
+package Config;
+
+our @networks = (
+       "10.0.10.0/24",
+       "10.0.11.0/24"
+);
+
+1;