diff options
author | Kristian Lyngstol <kristian@bohemians.org> | 2016-02-26 10:59:08 +0100 |
---|---|---|
committer | Kristian Lyngstol <kristian@bohemians.org> | 2016-02-26 10:59:08 +0100 |
commit | 9da864a8da29082369cdd2dd91a735b03577a117 (patch) | |
tree | 543d881f3746ddd4805dd0da449783eb42a8a92c /mbd | |
parent | 9ecc4690b2546ac117204207bec21ee1f6d585cf (diff) |
Archive old/unused things
Diffstat (limited to 'mbd')
-rw-r--r-- | mbd/access_list.pl | 294 | ||||
-rw-r--r-- | mbd/derpspan.c | 48 | ||||
-rwxr-xr-x | mbd/generate-helper-list.pl | 15 | ||||
-rwxr-xr-x | mbd/make-mbd-nets.pl | 26 | ||||
-rw-r--r-- | mbd/mbd-unicast-segfaulting.pl | 273 | ||||
-rw-r--r-- | mbd/mbd-unicast.pl | 254 | ||||
-rw-r--r-- | mbd/mbd.pl | 254 | ||||
-rw-r--r-- | mbd/mbd.pm | 50 | ||||
-rw-r--r-- | mbd/nets.pl | 171 | ||||
-rw-r--r-- | mbd/packetpusher.c | 127 | ||||
-rw-r--r-- | mbd/survey.pl | 10 |
11 files changed, 0 insertions, 1522 deletions
diff --git a/mbd/access_list.pl b/mbd/access_list.pl deleted file mode 100644 index 89a8182..0000000 --- a/mbd/access_list.pl +++ /dev/null @@ -1,294 +0,0 @@ - -package Config; - -sub game_id { - my ($data, $offset) = @_; - my $id = ((ord(substr($data, $offset, 1)) << 8) | ord(substr($data, $offset + 1, 1))); - return $id; -} - -our @access_list = ( - # half-life - untested (packet dump only) - { - name => 'Half-Life', - ports => [ 27015 ], - sizes => [ 16 ] - }, - - # cs 1.6 - verified - # (funker muligens for _alle_ source-spill inkl. hl2/cs:s) - { - name => 'CS:Source', - ports => [ "26900..26903", "27015..27017" ], - sizes => [ 25 ], - filter => sub { return (game_id(shift, 4) == 0x4325); } - }, - { - name => 'Left 4 Dead', - ports => [ "26900..26903", "27015..27017" ], - sizes => [ 25 ], - filter => sub { return (game_id(shift, 4) == 0x43f3); } - }, - { - name => 'CS 1.6', - ports => [ "26900..26903", "27015..27017" ], - sizes => [ 25 ], - filter => sub { return (game_id(shift, 4) == 0x5453); } - }, - { - name => 'Unknown Source-based game (ID 0x4326)', - ports => [ "26900..26903", "27015..27017" ], - sizes => [ 25 ], - filter => sub { return (game_id(shift, 4) == 0x4326); } - }, - { - name => 'Other Source game (unknown game ID)', - ports => [ "26900..26903", "27015..27017" ], - sizes => [ 25 ], - }, - { - name => 'Other Source game (unknown game ID, odd length 33)', - ports => [ "26900..26903", "27015..27017" ], - sizes => [ 33 ], - }, - { - name => 'Other Source game (unknown game ID, odd length 58)', - ports => [ "26900..26903", "27015..27017" ], - sizes => [ 58 ], - }, - { - name => 'Other Source game (unknown game ID, odd length 15)', - ports => [ "26900..26903", "27015..27017" ], - sizes => [ 15 ], - }, - - # doom 3 - verified - { - name => 'Doom 3', - ports => [ "27666" ], - sizes => [ 14 ] - }, - - # quake 1 - verified - { - name => 'Quake 1', - ports => [ 26000 ], - sizes => [ 12 ] - }, - - # q3a - tested with demo only - # rtcw: enemy territory - untested (packet dump only) - { - name => 'Quake 3 Arena, RTCW: ET', -# ports => [ "27960..27969" ], - ports => [ "27960..27961" ], - sizes => [ 15 ] - }, - - # bf2 - tested with demo only - # bf2142 reportedly uses same engine - { - name => 'BF2/BF2142', - ports => [ "29900" ], - sizes => [ 8 ] - }, - - # bf1942 - unverified (packet dump only) - { - name => 'BF1942', - ports => [ "22000..22010" ], - sizes => [ 8 ] - }, - - # quake 4 - tested with demo only, MUST select "internet" - { - name => 'Quake 4', - ports => [ 27950, 28004 ], - sizes => [ 14 ] - }, - - # quake 2 - untested (packet dump only) - { - name => 'Quake 2', - ports => [ 27910 ], - sizes => [ 11 ] - }, - - # warcraft 3 - untested (packet dump only) - { - name => 'Warcraft 3: Reign of Chaos (1.00)', - ports => [ 6112 ], - sizes => [ 16 ], - filter => sub { my $data = shift; return (ord(substr($data, 1, 1)) == 0x2f) && game_id($data, 4) == 0x3352 && ord(substr($data, 8, 1)) == 0; } - }, - { - name => 'Warcraft 3: Reign of Chaos (1.07)', - ports => [ 6112 ], - sizes => [ 16 ], - filter => sub { my $data = shift; return (ord(substr($data, 1, 1)) == 0x2f) && game_id($data, 4) == 0x3352 && ord(substr($data, 8, 1)) == 7; } - }, - { - name => 'Warcraft 3: Reign of Chaos (1.20)', - ports => [ 6112 ], - sizes => [ 16 ], - filter => sub { my $data = shift; return (ord(substr($data, 1, 1)) == 0x2f) && game_id($data, 4) == 0x3352 && ord(substr($data, 8, 1)) == 20; } - }, - { - name => 'Warcraft 3: Reign of Chaos (1.22)', - ports => [ 6112 ], - sizes => [ 16 ], - filter => sub { my $data = shift; return (ord(substr($data, 1, 1)) == 0x2f) && game_id($data, 4) == 0x3352 && ord(substr($data, 8, 1)) == 22; } - }, - { - name => 'Warcraft 3: Reign of Chaos (1.23)', - ports => [ 6112 ], - sizes => [ 16 ], - filter => sub { my $data = shift; return (ord(substr($data, 1, 1)) == 0x2f) && game_id($data, 4) == 0x3352 && ord(substr($data, 8, 1)) == 23; } - }, - { - name => 'Warcraft 3: Reign of Chaos (other patch level)', - ports => [ 6112 ], - sizes => [ 16 ], - filter => sub { my $data = shift; return (ord(substr($data, 1, 1)) == 0x2f) && game_id($data, 4) == 0x3352; } - }, - { - name => 'Warcraft 3: The Frozen Throne (1.17)', - ports => [ 6112 ], - sizes => [ 16 ], - filter => sub { my $data = shift; return (ord(substr($data, 1, 1)) == 0x2f) && game_id($data, 4) == 0x5058 && ord(substr($data, 8, 1)) == 17; } - }, - { - name => 'Warcraft 3: The Frozen Throne (1.18)', - ports => [ 6112 ], - sizes => [ 16 ], - filter => sub { my $data = shift; return (ord(substr($data, 1, 1)) == 0x2f) && game_id($data, 4) == 0x5058 && ord(substr($data, 8, 1)) == 18; } - }, - { - name => 'Warcraft 3: The Frozen Throne (1.20)', - ports => [ 6112 ], - sizes => [ 16 ], - filter => sub { my $data = shift; return (ord(substr($data, 1, 1)) == 0x2f) && game_id($data, 4) == 0x5058 && ord(substr($data, 8, 1)) == 20; } - }, - { - name => 'Warcraft 3: The Frozen Throne (1.21)', - ports => [ 6112 ], - sizes => [ 16 ], - filter => sub { my $data = shift; return (ord(substr($data, 1, 1)) == 0x2f) && game_id($data, 4) == 0x5058 && ord(substr($data, 8, 1)) == 21; } - }, - { - name => 'Warcraft 3: The Frozen Throne (1.22)', - ports => [ 6112 ], - sizes => [ 16 ], - filter => sub { my $data = shift; return (ord(substr($data, 1, 1)) == 0x2f) && game_id($data, 4) == 0x5058 && ord(substr($data, 8, 1)) == 22; } - }, - { - name => 'Warcraft 3: The Frozen Throne (1.23)', - ports => [ 6112 ], - sizes => [ 16 ], - filter => sub { my $data = shift; return (ord(substr($data, 1, 1)) == 0x2f) && game_id($data, 4) == 0x5058 && ord(substr($data, 8, 1)) == 23; } - }, - { - name => 'Warcraft 3: The Frozen Throne (1.26)', - ports => [ 6112 ], - sizes => [ 16 ], - filter => sub { my $data = shift; return (ord(substr($data, 1, 1)) == 0x2f) && game_id($data, 4) == 0x5058 && ord(substr($data, 8, 1)) == 26; } - }, - { - name => 'Warcraft 3: The Frozen Throne (other patch level)', - ports => [ 6112 ], - sizes => [ 16 ], - filter => sub { my $data = shift; return (ord(substr($data, 1, 1)) == 0x2f) && game_id($data, 4) == 0x5058; } - }, - { - name => 'Warcraft 3 (unknown version)', -# ports => [ "6112..6119" ], - ports => [ 6112 ], - sizes => [ 16 ], - filter => sub { my $data = shift; return (ord(substr($data, 1, 1)) == 0x2f) && game_id($data, 4) != 0x5058 && game_id($data, 4) != 0x3352; } - }, - { - name => 'Warcraft 3 (unknown version, odd length)', - ports => [ 6112 ], - sizes => [ 19 ], - }, - - # ut2003/ut2004 - untested (packet dump only) - { - name => 'UT2003/UT2004', - ports => [ 10777 ], - sizes => [ 5 ] - }, - - # soldat - untested (packet dump only) - { - name => 'Soldat', - ports => [ 23073 ], - sizes => [ 8 ] - }, - - # starcraft - untested (packet dump only) - { - name => 'Starcraft', - ports => [ 6111, 6112 ], - sizes => [ 8 ], - filter => sub { return (game_id(shift, 0) == 0x08ef); } - }, - { - name => 'Starcraft: Brood War', - ports => [ 6111, 6112 ], - sizes => [ 8 ], - filter => sub { return (game_id(shift, 0) == 0xf733); } - }, - { - name => 'Starcraft (unknown game ID)', - ports => [ 6111, 6112 ], - sizes => [ 8 ], - filter => sub { my $id = game_id(shift, 0); return ($id != 0x08ef && $id != 0xf733); } - }, - - # trackmania nations - untested (packet dump only) - { - name => 'Trackmania Nations', - ports => [ "2350" ], - sizes => [ 42, 30 ] - }, - - # company of heroes - untested (packet dump only) - { - name => 'Company of Heroes', - ports => [ 9100 ], - sizes => [ 39 ] - }, - - # command & conquer 3 - untested (packet dump only, reported to have some kind - # of chat functionality) -# { -# name => 'Command & Conquer 3', -# ports => [ "8086..8093" ], -# sizes => [ 476 ], -# filter => sub { return 0; } -# }, - - # openttd - { - name => 'OpenTTD', - ports => [ 3979 ], - sizes => [ 3 ] - }, - - # CoD4 - { - name => 'Call of Duty 4', - ports => [ 28960 ], - sizes => [ 15 ], - }, - - # Far Cry 2 - { - name => 'Far Cry 2', - ports => [ 9004 ], - sizes => [ 114, 118, 122, 126 ], - }, - - # unreal tournament, port 9777? -) diff --git a/mbd/derpspan.c b/mbd/derpspan.c deleted file mode 100644 index b9fb362..0000000 --- a/mbd/derpspan.c +++ /dev/null @@ -1,48 +0,0 @@ -// gcc -O2 -o derspan derspan.c -lpcap -std=gnu99 -Wall - -#include <pcap.h> -#include <stdlib.h> -#include <netinet/ip.h> -#include <stdint.h> -#include <stdio.h> - -int rawsock; - -void my_callback(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) -{ - int len = h->caplen; - if (len < 40) { - //printf("skipped short packet\n"); - return; - } - if (bytes[14] != 0x88 || bytes[15] != 0xbe) { - //printf("skipped non-ethernet packet\n"); - return; - } - if (bytes[36] != 0x08 || bytes[37] != 0x00) { - //printf("skipped non-IPv4 packet\n"); - return; - } - - struct sockaddr_in self; - self.sin_family = AF_INET; - self.sin_addr.s_addr = htonl(0x7f000001); // localhost - self.sin_port = htons(1337); - - sendto(rawsock, bytes + 38, len - 38, 0, (struct sockaddr *)&self, sizeof(self)); -} - -int main(int argc, char **argv) -{ - rawsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); - if (rawsock == -1) { - perror("socket"); - exit(0); - } - - pcap_t *pcap = pcap_open_live(argv[1], 1500, 1, 1000, NULL); - pcap_activate(pcap); - pcap_loop(pcap, -1, my_callback, NULL); - return 0; -} - diff --git a/mbd/generate-helper-list.pl b/mbd/generate-helper-list.pl deleted file mode 100755 index fd89475..0000000 --- a/mbd/generate-helper-list.pl +++ /dev/null @@ -1,15 +0,0 @@ -#! /usr/bin/perl -use strict; -use warnings; -require './access_list.pl'; -require './nets.pl'; -require './mbd.pm'; - -my @ports = mbd::find_all_ports(); - -print "no ip forward-protocol udp 137\n"; -print "no ip forward-protocol udp 138\n"; - -for my $port (@ports) { - print "ip forward-protocol udp $port\n"; -} diff --git a/mbd/make-mbd-nets.pl b/mbd/make-mbd-nets.pl deleted file mode 100755 index 7f6ec97..0000000 --- a/mbd/make-mbd-nets.pl +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/perl -I /root/tgmanage/ -use strict; -use warnings; - -unless (@ARGV > 0) { - print "No arguments. Need netlist.txt.\n"; - exit 1; -} - -my $n = open(NETLIST, "$ARGV[0]") or die ("Cannot open netlist.txt"); - -print "# Autogenerated. Do not touch!\n"; -print "package Config;\n"; -print "our \@networks = (\n"; - -while(<NETLIST>) { - next if /^(.*#|\s+$)/; # skip if comment, or blank line - - chomp; - my ($v4_net, $v6_net, $net_name) = split; - - print "\t\"$v4_net\",\n"; -} - -print ");\n"; -print "1;\n"; diff --git a/mbd/mbd-unicast-segfaulting.pl b/mbd/mbd-unicast-segfaulting.pl deleted file mode 100644 index c167511..0000000 --- a/mbd/mbd-unicast-segfaulting.pl +++ /dev/null @@ -1,273 +0,0 @@ -#! /usr/bin/perl -use strict; -use warnings; -use Socket; -use Net::CIDR; -use Net::RawIP; -use Time::HiRes; -require './access_list.pl'; -require './nets.pl'; -require './survey.pl'; -require './mbd.pm'; -use lib '../include'; -use nms; -use strict; -use warnings; -use threads; - -# Mark packets with DSCP CS7 -my $tos = 56; - -my ($dbh, $q); - -sub fhbits { - my $bits = 0; - for my $fh (@_) { - vec($bits, fileno($fh), 1) = 1; - } - return $bits; -} - -# used for rate limiting -my %last_sent = (); - -# for own surveying -my %active_surveys = (); -my %last_survey = (); - -my %cidrcache = (); -sub cache_cidrlookup { - my ($addr, $net) = @_; - my $key = $addr . " " . $net; - - if (!exists($cidrcache{$key})) { - $cidrcache{$key} = Net::CIDR::cidrlookup($addr, $net); - } - return $cidrcache{$key}; -} - -my %rangecache = (); -sub cache_cidrrange { - my ($net) = @_; - - if (!exists($rangecache{$net})) { - my ($range) = Net::CIDR::cidr2range($net); - $range =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)-(\d+)\.(\d+)\.(\d+)\.(\d+)/ or die "Did not understand range: $range"; - my @range = (); - for my $l (($4+1)..($8-1)) { - push @range, "$1.$2.$3.$l"; - } - ($rangecache{$net}) = \@range; - } - - return @{$rangecache{$net}}; -} - -open LOG, ">>", "mbd.log"; - -my @ports = ( mbd::find_all_ports() , $Config::survey_port_low .. $Config::survey_port_high ); - -# 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); - my $now = [Time::HiRes::gettimeofday]; - - # First of all, close any surveys that are due. - for my $sport (keys %active_surveys) { - my $age = Time::HiRes::tv_interval($active_surveys{$sport}{start}, $now); - if ($age > $Config::survey_time && $active_surveys{$sport}{active}) { - my $hexdump = join(' ', map { sprintf "0x%02x", ord($_) } (split //, $active_surveys{$sport}{data})); - print "Survey ($hexdump) for '" . $Config::access_list[$active_surveys{$sport}{entry}]->{name} . "'/" . - $active_surveys{$sport}{dport} . ": " . $active_surveys{$sport}{num} . " active servers.\n"; - $active_surveys{$sport}{active} = 0; - - # (re)connect to the database if needed - if (!defined($dbh) || !$dbh->ping) { - $dbh = nms::db_connect(); - $q = $dbh->prepare("INSERT INTO mbd_log (ts,game,port,description,active_servers) VALUES (CURRENT_TIMESTAMP,?,?,?,?)") - or die "Couldn't prepare query"; - } - $q->execute($active_surveys{$sport}{entry}, $active_surveys{$sport}{dport}, $Config::access_list[$active_surveys{$sport}{entry}]->{name}, $active_surveys{$sport}{num}); - } - if ($age > $Config::survey_time * 3.0) { - delete $active_surveys{$sport}; - } - } - - 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); - - # Check if this is a survey reply - if ($dport >= $Config::survey_port_low && $dport <= $Config::survey_port_high) { - if (!exists($active_surveys{$dport})) { - print "WARNING: Unknown survey port $dport, ignoring\n"; - next; - } - if (!$active_surveys{$dport}{active}) { - # remains - next; - } - - ++$active_surveys{$dport}{num}; - - next; - } - - # Rate limiting - if (exists($last_sent{$saddr}{$dport})) { - my $elapsed = Time::HiRes::tv_interval($last_sent{$saddr}{$dport}, $now); - if ($elapsed < 1.0) { - print LOG "$dport $size 2\n"; - print inet_ntoa($saddr), ", $dport, $size bytes => rate-limited ($elapsed secs since last)\n"; - next; - } - } - - # We don't get the packet's destination address, but I guess this should do... - # Check against the ACL. - my $pass = 0; - my $entry = -1; - for my $rule (@Config::access_list) { - ++$entry; - - next unless (mbd::match_ranges($dport, $rule->{'ports'})); - next unless (mbd::match_ranges($size, $rule->{'sizes'})); - - if ($rule->{'filter'}) { - next unless ($rule->{'filter'}($data)); - } - - $pass = 1; - last; - } - - print LOG "$dport $size $pass\n"; - - if (!$pass) { - print inet_ntoa($saddr), ", $dport, $size bytes => filtered\n"; - next; - } - - $last_sent{$saddr}{$dport} = $now; - - # The packet is OK! Do we already have a recent enough survey - # for this port, or should we use this packet? - my $survey = 1; - if (exists($last_survey{$entry . "/" . $dport})) { - my $age = Time::HiRes::tv_interval($last_survey{$entry . "/" . $dport}, $now); - if ($age < $Config::survey_freq) { - $survey = 0; - } - } - - # New survey; find an unused port - my $survey_sport; - if ($survey) { - for my $port ($Config::survey_port_low..$Config::survey_port_high) { - if (!exists($active_surveys{$port})) { - $survey_sport = $port; - - $active_surveys{$port} = { - start => $now, - active => 1, - dport => $dport, - entry => $entry, - num => 0, - data => $data, - }; - $last_survey{$entry . "/" . $dport} = $now; - - last; - } - } - - if (!defined($survey_sport)) { - print "WARNING: no free survey source ports, not surveying.\n"; - $survey = 0; - } - } - - # precache - for my $net (@Config::networks) { - cache_cidrrange($net); - cache_cidrlookup(inet_ntoa($saddr), $net); - } - - threads->create(sub { - my $sendsock = Net::RawIP->new({udp => {}}); - my ($survey_sport, $dport, $data) = @_; - - my $num_nets = 0; - for my $net (@Config::networks) { - my @daddrs = cache_cidrrange($net); - - if ($survey) { - for my $daddr (@daddrs) { - $sendsock->set({ - ip => { - saddr => $Config::survey_ip, - daddr => $daddr, - tos => $tos - }, - udp => { - source => $survey_sport, - dest => $dport, - data => $data - } - }); - $sendsock->send; - } - } - - next if (cache_cidrlookup(inet_ntoa($saddr), $net)); - - for my $daddr (@daddrs) { - $sendsock->set({ - ip => { - saddr => inet_ntoa($saddr), - daddr => $daddr, - tos => $tos - }, - udp => { - source => $sport, - dest => $dport, - data => $data - } - }); - $sendsock->send; - } - - ++$num_nets; - } - if ($survey) { - print inet_ntoa($saddr), ", $dport, $size bytes => ($num_nets networks) [+survey from port $survey_sport]\n"; - } else { - print inet_ntoa($saddr), ", $dport, $size bytes => ($num_nets networks)\n"; - } - }, $survey_sport, $dport, $data)->detach(); - } -} - diff --git a/mbd/mbd-unicast.pl b/mbd/mbd-unicast.pl deleted file mode 100644 index 6e63dee..0000000 --- a/mbd/mbd-unicast.pl +++ /dev/null @@ -1,254 +0,0 @@ -#! /usr/bin/perl -use strict; -use warnings; -use Socket; -use Net::CIDR; -use Net::RawIP; -use Time::HiRes; -require './access_list.pl'; -require './nets.pl'; -require './survey.pl'; -require './mbd.pm'; -use lib '../include'; -use nms; -use strict; -use warnings; -use threads; - -# Mark packets with DSCP CS7 -my $tos = 56; - -my ($dbh, $q); - -sub fhbits { - my $bits = 0; - for my $fh (@_) { - vec($bits, fileno($fh), 1) = 1; - } - return $bits; -} - -# used for rate limiting -my %last_sent = (); - -# for own surveying -my %active_surveys = (); -my %last_survey = (); - -my %cidrcache = (); -sub cache_cidrlookup { - my ($addr, $net) = @_; - my $key = $addr . " " . $net; - - if (!exists($cidrcache{$key})) { - $cidrcache{$key} = Net::CIDR::cidrlookup($addr, $net); - } - return $cidrcache{$key}; -} - -my %rangecache = (); -sub cache_cidrrange { - my ($net) = @_; - - if (!exists($rangecache{$net})) { - my ($range) = Net::CIDR::cidr2range($net); - $range =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)-(\d+)\.(\d+)\.(\d+)\.(\d+)/ or die "Did not understand range: $range"; - my @range = (); - for my $l (($4+1)..($8-1)) { - push @range, "$1.$2.$3.$l"; - } - ($rangecache{$net}) = \@range; - } - - return @{$rangecache{$net}}; -} - -open LOG, ">>", "mbd.log"; - -my @ports = ( mbd::find_all_ports() , $Config::survey_port_low .. $Config::survey_port_high ); - -# 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"; - -open PKTS, "| ./packetpusher" - or die "./packetpusher: $!"; - -# Main loop -while (1) { - my $rin = fhbits(@socks); - my $rout; - - my $nfound = select($rout=$rin, undef, undef, undef); - my $now = [Time::HiRes::gettimeofday]; - - # First of all, close any surveys that are due. - for my $sport (keys %active_surveys) { - my $age = Time::HiRes::tv_interval($active_surveys{$sport}{start}, $now); - if ($age > $Config::survey_time && $active_surveys{$sport}{active}) { - my $hexdump = join(' ', map { sprintf "0x%02x", ord($_) } (split //, $active_surveys{$sport}{data})); - print "Survey ($hexdump) for '" . $Config::access_list[$active_surveys{$sport}{entry}]->{name} . "'/" . - $active_surveys{$sport}{dport} . ": " . $active_surveys{$sport}{num} . " active servers.\n"; - $active_surveys{$sport}{active} = 0; - - # (re)connect to the database if needed - if (!defined($dbh) || !$dbh->ping) { - $dbh = nms::db_connect(); - $q = $dbh->prepare("INSERT INTO mbd_log (ts,game,port,description,active_servers) VALUES (CURRENT_TIMESTAMP,?,?,?,?)") - or die "Couldn't prepare query"; - } - $q->execute($active_surveys{$sport}{entry}, $active_surveys{$sport}{dport}, $Config::access_list[$active_surveys{$sport}{entry}]->{name}, $active_surveys{$sport}{num}); - } - if ($age > $Config::survey_time * 3.0) { - delete $active_surveys{$sport}; - } - } - - 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); - - # Check if this is a survey reply - if ($dport >= $Config::survey_port_low && $dport <= $Config::survey_port_high) { - if (!exists($active_surveys{$dport})) { - print "WARNING: Unknown survey port $dport, ignoring\n"; - next; - } - if (!$active_surveys{$dport}{active}) { - # remains - next; - } - - ++$active_surveys{$dport}{num}; - - next; - } - - # Rate limiting - if (exists($last_sent{$saddr}{$dport})) { - my $elapsed = Time::HiRes::tv_interval($last_sent{$saddr}{$dport}, $now); - if ($elapsed < 1.0) { - print LOG "$dport $size 2\n"; - print inet_ntoa($saddr), ", $dport, $size bytes => rate-limited ($elapsed secs since last)\n"; - next; - } - } - - # We don't get the packet's destination address, but I guess this should do... - # Check against the ACL. - my $pass = 0; - my $entry = -1; - for my $rule (@Config::access_list) { - ++$entry; - - next unless (mbd::match_ranges($dport, $rule->{'ports'})); - next unless (mbd::match_ranges($size, $rule->{'sizes'})); - - if ($rule->{'filter'}) { - next unless ($rule->{'filter'}($data)); - } - - $pass = 1; - last; - } - - print LOG "$dport $size $pass\n"; - - if (!$pass) { - print inet_ntoa($saddr), ", $dport, $size bytes => filtered\n"; - next; - } - - $last_sent{$saddr}{$dport} = $now; - - # The packet is OK! Do we already have a recent enough survey - # for this port, or should we use this packet? - my $survey = 1; - if (exists($last_survey{$entry . "/" . $dport})) { - my $age = Time::HiRes::tv_interval($last_survey{$entry . "/" . $dport}, $now); - if ($age < $Config::survey_freq) { - $survey = 0; - } - } - - # New survey; find an unused port - my $survey_sport; - if ($survey) { - for my $port ($Config::survey_port_low..$Config::survey_port_high) { - if (!exists($active_surveys{$port})) { - $survey_sport = $port; - - $active_surveys{$port} = { - start => $now, - active => 1, - dport => $dport, - entry => $entry, - num => 0, - data => $data, - }; - $last_survey{$entry . "/" . $dport} = $now; - - last; - } - } - - if (!defined($survey_sport)) { - print "WARNING: no free survey source ports, not surveying.\n"; - $survey = 0; - } - } - - # precache - for my $net (@Config::networks) { - cache_cidrrange($net); - cache_cidrlookup(inet_ntoa($saddr), $net); - } - - my @packets = (); - - my $num_nets = 0; - for my $net (@Config::networks) { - my @daddrs = cache_cidrrange($net); - - if ($survey) { - for my $daddr (@daddrs) { - push @packets, [ $Config::survey_ip, $survey_sport, $daddr, $dport ]; - } - } - - next if (cache_cidrlookup(inet_ntoa($saddr), $net)); - - for my $daddr (@daddrs) { - push @packets, [ inet_ntoa($saddr), $sport, $daddr, $dport ]; - } - - ++$num_nets; - } - if ($survey) { - print inet_ntoa($saddr), ", $dport, $size bytes => ($num_nets networks) [+survey from port $survey_sport]\n"; - } else { - print inet_ntoa($saddr), ", $dport, $size bytes => ($num_nets networks)\n"; - } - - printf PKTS "%d %s\n", scalar @packets, unpack('h*', $data); - for my $pkt (@packets) { - printf PKTS "%s %s %s %s\n", $pkt->[0], $pkt->[1], $pkt->[2], $pkt->[3]; - } - } -} - diff --git a/mbd/mbd.pl b/mbd/mbd.pl deleted file mode 100644 index 065e76c..0000000 --- a/mbd/mbd.pl +++ /dev/null @@ -1,254 +0,0 @@ -#! /usr/bin/perl -use strict; -use warnings; -use Socket; -use Net::CIDR; -use Net::RawIP; -use Time::HiRes; -require './access_list.pl'; -require './nets.pl'; -require './survey.pl'; -require './mbd.pm'; -use lib '../include'; -use nms; -use strict; -use warnings; - -# Mark packets with DSCP CS7 -my $tos = 56; - -my ($dbh, $q); - -sub fhbits { - my $bits = 0; - for my $fh (@_) { - vec($bits, fileno($fh), 1) = 1; - } - return $bits; -} - -# used for rate limiting -my %last_sent = (); - -# for own surveying -my %active_surveys = (); -my %last_survey = (); - -my %cidrcache = (); -sub cache_cidrlookup { - my ($addr, $net) = @_; - my $key = $addr . " " . $net; - - if (!exists($cidrcache{$key})) { - $cidrcache{$key} = Net::CIDR::cidrlookup($addr, $net); - } - return $cidrcache{$key}; -} - -my %rangecache = (); -sub cache_cidrrange { - my ($net) = @_; - - if (!exists($rangecache{$net})) { - ($rangecache{$net}) = Net::CIDR::cidr2range($net); - } - - return $rangecache{$net}; -} - -open LOG, ">>", "mbd.log"; - -my @ports = ( mbd::find_all_ports() , $Config::survey_port_low .. $Config::survey_port_high ); - -# 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); - my $now = [Time::HiRes::gettimeofday]; - - # First of all, close any surveys that are due. - for my $sport (keys %active_surveys) { - my $age = Time::HiRes::tv_interval($active_surveys{$sport}{start}, $now); - if ($age > $Config::survey_time && $active_surveys{$sport}{active}) { - my $hexdump = join(' ', map { sprintf "0x%02x", ord($_) } (split //, $active_surveys{$sport}{data})); - print "Survey ($hexdump) for '" . $Config::access_list[$active_surveys{$sport}{entry}]->{name} . "'/" . - $active_surveys{$sport}{dport} . ": " . $active_surveys{$sport}{num} . " active servers.\n"; - $active_surveys{$sport}{active} = 0; - - # (re)connect to the database if needed - if (!defined($dbh) || !$dbh->ping) { - $dbh = nms::db_connect(); - $q = $dbh->prepare("INSERT INTO mbd_log (ts,game,port,description,active_servers) VALUES (CURRENT_TIMESTAMP,?,?,?,?)") - or die "Couldn't prepare query"; - } - $q->execute($active_surveys{$sport}{entry}, $active_surveys{$sport}{dport}, $Config::access_list[$active_surveys{$sport}{entry}]->{name}, $active_surveys{$sport}{num}); - } - if ($age > $Config::survey_time * 3.0) { - delete $active_surveys{$sport}; - } - } - - 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); - - # Check if this is a survey reply - if ($dport >= $Config::survey_port_low && $dport <= $Config::survey_port_high) { - if (!exists($active_surveys{$dport})) { - print "WARNING: Unknown survey port $dport, ignoring\n"; - next; - } - if (!$active_surveys{$dport}{active}) { - # remains - next; - } - - ++$active_surveys{$dport}{num}; - - next; - } - - # Rate limiting - if (exists($last_sent{$saddr}{$dport})) { - my $elapsed = Time::HiRes::tv_interval($last_sent{$saddr}{$dport}, $now); - if ($elapsed < 1.0) { - print LOG "$dport $size 2\n"; - print inet_ntoa($saddr), ", $dport, $size bytes => rate-limited ($elapsed secs since last)\n"; - next; - } - } - - # We don't get the packet's destination address, but I guess this should do... - # Check against the ACL. - my $pass = 0; - my $entry = -1; - for my $rule (@Config::access_list) { - ++$entry; - - next unless (mbd::match_ranges($dport, $rule->{'ports'})); - next unless (mbd::match_ranges($size, $rule->{'sizes'})); - - if ($rule->{'filter'}) { - next unless ($rule->{'filter'}($data)); - } - - $pass = 1; - last; - } - - print LOG "$dport $size $pass\n"; - - if (!$pass) { - print inet_ntoa($saddr), ", $dport, $size bytes => filtered\n"; - next; - } - - $last_sent{$saddr}{$dport} = $now; - - # The packet is OK! Do we already have a recent enough survey - # for this port, or should we use this packet? - my $survey = 1; - if (exists($last_survey{$entry . "/" . $dport})) { - my $age = Time::HiRes::tv_interval($last_survey{$entry . "/" . $dport}, $now); - if ($age < $Config::survey_freq) { - $survey = 0; - } - } - - # New survey; find an unused port - my $survey_sport; - if ($survey) { - for my $port ($Config::survey_port_low..$Config::survey_port_high) { - if (!exists($active_surveys{$port})) { - $survey_sport = $port; - - $active_surveys{$port} = { - start => $now, - active => 1, - dport => $dport, - entry => $entry, - num => 0, - data => $data, - }; - $last_survey{$entry . "/" . $dport} = $now; - - last; - } - } - - if (!defined($survey_sport)) { - print "WARNING: no free survey source ports, not surveying.\n"; - $survey = 0; - } - } - - my $num_nets = 0; - for my $net (@Config::networks) { - my ($range) = cache_cidrrange($net); - $range =~ /-(.*?)$/; - my $broadcast = $1; - - if ($survey) { - $sendsock->set({ - ip => { - saddr => $Config::survey_ip, - daddr => $broadcast, - tos => $tos - }, - udp => { - source => $survey_sport, - dest => $dport, - data => $data - } - }); - $sendsock->send; - } - - next if (cache_cidrlookup(inet_ntoa($saddr), $net)); - - $sendsock->set({ - ip => { - saddr => inet_ntoa($saddr), - daddr => $broadcast, - tos => $tos - }, - udp => { - source => $sport, - dest => $dport, - data => $data - } - }); - $sendsock->send; - - ++$num_nets; - } - - if ($survey) { - print inet_ntoa($saddr), ", $dport, $size bytes => ($num_nets networks) [+survey from port $survey_sport]\n"; - } else { - print inet_ntoa($saddr), ", $dport, $size bytes => ($num_nets networks)\n"; - } - } -} - diff --git a/mbd/mbd.pm b/mbd/mbd.pm deleted file mode 100644 index b844e5b..0000000 --- a/mbd/mbd.pm +++ /dev/null @@ -1,50 +0,0 @@ -#! /usr/bin/perl -use strict; -use warnings; -use Socket; -use Net::CIDR; -use Net::RawIP; -require './access_list.pl'; -require './nets.pl'; - -package mbd; - -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 find_all_ports { - # 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; - return @ports; -} - -1; diff --git a/mbd/nets.pl b/mbd/nets.pl deleted file mode 100644 index 3298657..0000000 --- a/mbd/nets.pl +++ /dev/null @@ -1,171 +0,0 @@ -# Autogenerated. Do not touch! -package Config; -our @networks = ( - "176.110.98.0/24", - "176.110.99.0/24", - "176.110.100.0/24", - "176.110.102.0/24", - "176.110.103.0/24", - "176.110.106.0/24", - "176.110.107.0/24", - "176.110.108.0/22", - "176.110.112.0/24", - "176.110.113.0/24", - "176.110.114.0/24", - "176.110.115.0/24", - "176.110.116.0/24", - "176.110.117.0/24", - "176.110.118.0/24", - "176.110.119.0/24", - "176.110.120.0/24", - "176.110.121.0/24", - "176.110.122.0/24", - "176.110.123.0/24", - "176.110.124.0/24", - "176.110.126.0/24", - "176.110.2.0/25", - "176.110.2.128/25", - "176.110.4.0/25", - "176.110.4.128/25", - "176.110.6.0/25", - "176.110.6.128/25", - "176.110.8.0/25", - "176.110.8.128/25", - "176.110.10.0/25", - "176.110.10.128/25", - "176.110.11.0/25", - "176.110.11.128/25", - "176.110.12.0/25", - "176.110.12.128/25", - "176.110.13.0/25", - "176.110.13.128/25", - "176.110.14.0/25", - "176.110.14.128/25", - "176.110.15.0/25", - "176.110.15.128/25", - "176.110.16.0/25", - "176.110.16.128/25", - "176.110.17.0/25", - "176.110.17.128/25", - "176.110.18.0/25", - "176.110.18.128/25", - "176.110.19.0/25", - "176.110.19.128/25", - "176.110.20.0/25", - "176.110.20.128/25", - "176.110.21.0/25", - "176.110.21.128/25", - "176.110.22.0/25", - "176.110.22.128/25", - "176.110.23.0/25", - "176.110.23.128/25", - "176.110.24.0/25", - "176.110.24.128/25", - "176.110.25.0/25", - "176.110.25.128/25", - "176.110.26.0/25", - "176.110.26.128/25", - "176.110.27.0/25", - "176.110.27.128/25", - "176.110.29.0/25", - "176.110.29.128/25", - "176.110.31.0/25", - "176.110.31.128/25", - "176.110.33.0/25", - "176.110.33.128/25", - "176.110.35.0/25", - "176.110.35.128/25", - "176.110.37.0/25", - "176.110.37.128/25", - "176.110.39.0/25", - "176.110.39.128/25", - "176.110.41.0/25", - "176.110.41.128/25", - "176.110.43.0/25", - "176.110.43.128/25", - "176.110.44.0/25", - "176.110.44.128/25", - "176.110.45.0/25", - "176.110.45.128/25", - "176.110.46.0/25", - "176.110.46.128/25", - "176.110.47.0/25", - "176.110.47.128/25", - "176.110.48.0/25", - "176.110.48.128/25", - "176.110.49.0/25", - "176.110.49.128/25", - "176.110.50.0/25", - "176.110.50.128/25", - "176.110.51.0/25", - "176.110.51.128/25", - "176.110.52.0/25", - "176.110.52.128/25", - "176.110.53.0/25", - "176.110.53.128/25", - "176.110.54.0/25", - "176.110.54.128/25", - "176.110.55.0/25", - "176.110.55.128/25", - "176.110.56.0/25", - "176.110.56.128/25", - "176.110.57.0/25", - "176.110.57.128/25", - "176.110.58.0/25", - "176.110.58.128/25", - "176.110.59.0/25", - "176.110.59.128/25", - "176.110.60.0/25", - "176.110.60.128/25", - "176.110.61.0/25", - "176.110.61.128/25", - "176.110.62.0/25", - "176.110.62.128/25", - "176.110.63.0/25", - "176.110.63.128/25", - "176.110.64.0/25", - "176.110.64.128/25", - "176.110.65.0/25", - "176.110.65.128/25", - "176.110.66.0/25", - "176.110.66.128/25", - "176.110.67.0/25", - "176.110.67.128/25", - "176.110.68.0/25", - "176.110.68.128/25", - "176.110.69.0/25", - "176.110.69.128/25", - "176.110.70.0/25", - "176.110.70.128/25", - "176.110.71.0/25", - "176.110.71.128/25", - "176.110.72.0/25", - "176.110.72.128/25", - "176.110.73.0/25", - "176.110.73.128/25", - "176.110.74.0/25", - "176.110.74.128/25", - "176.110.75.0/25", - "176.110.75.128/25", - "176.110.76.0/25", - "176.110.76.128/25", - "176.110.77.0/25", - "176.110.77.128/25", - "176.110.79.0/25", - "176.110.79.128/25", - "176.110.81.0/25", - "176.110.81.128/25", - "176.110.83.0/25", - "176.110.83.128/25", - "176.110.84.0/25", - "176.110.84.128/25", - "176.110.85.0/25", - "176.110.85.128/25", - "176.110.86.0/25", - "176.110.86.128/25", - "176.110.87.0/25", - "176.110.87.128/25", - "176.110.88.0/25", - "176.110.88.128/25", -); -1; diff --git a/mbd/packetpusher.c b/mbd/packetpusher.c deleted file mode 100644 index c21a084..0000000 --- a/mbd/packetpusher.c +++ /dev/null @@ -1,127 +0,0 @@ -#include <stdio.h> -#include <sys/socket.h> -#include <stdlib.h> -#include <string.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/udp.h> -#include <stdint.h> -#include <arpa/inet.h> - -char encoded_pkt[4096], workspace[4096]; -unsigned char pkt[2048]; - -typedef uint32_t u_int32_t; - -u_int32_t checksum(unsigned char *buf, unsigned nbytes, u_int32_t sum) -{ - int i; - /* Checksum all the pairs of bytes first... */ - for (i = 0; i < (nbytes & ~1U); i += 2) { - sum += (u_int16_t)ntohs(*((u_int16_t *)(buf + i))); - if (sum > 0xFFFF) - sum -= 0xFFFF; - } - - /* - * If there's a single byte left over, checksum it, too. - * Network byte order is big-endian, so the remaining byte is - * the high byte. - */ - - if (i < nbytes) { - sum += buf[i] << 8; - if (sum > 0xFFFF) - sum -= 0xFFFF; - } - - return (sum); -} - -u_int32_t wrapsum(u_int32_t sum) -{ - sum = ~sum & 0xFFFF; - return (htons(sum)); -} - -int main(int argc, char **argv) -{ - int sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); - if (sock == -1) { - perror("socket"); - exit(1); - } - - for ( ;; ) { - int num_pkts; - int ret = scanf("%d %s", &num_pkts, encoded_pkt); - if (ret != 2) { - fprintf(stderr, "error parsing! ret=%d\n", ret); - exit(1); - } - if ((strlen(encoded_pkt) % 2) != 0) { - fprintf(stderr, "hex packet has odd length\n"); - exit(1); - } - - // de-hex packet - for (int i = 0; i < strlen(encoded_pkt); i += 2) { - char c[3]; - c[0] = encoded_pkt[i]; - c[1] = encoded_pkt[i + 1]; - c[2] = 0; - int h = strtol(c, NULL, 16); - pkt[i / 2] = h; - } - - int datalen = strlen(encoded_pkt) / 2; - - for (int i = 0; i < num_pkts; ++i) { - char from_ip[256], to_ip[256]; - int sport, dport; - if (scanf("%s %d %s %d", from_ip, &sport, to_ip, &dport) != 4) { - fprintf(stderr, "error parsing packet %d!\n", i); - exit(1); - } - - // IP header - struct iphdr *ip = (struct iphdr *)workspace; - ip->version = 4; - ip->ihl = 5; - ip->tos = 0; - ip->tot_len = htons(datalen + sizeof(struct iphdr) + sizeof(struct udphdr)); - ip->id = 0; - ip->frag_off = 0; - ip->ttl = 64; - ip->protocol = 17; // UDP - ip->saddr = inet_addr(from_ip); - ip->daddr = inet_addr(to_ip); - ip->check = 0; - ip->check = wrapsum(checksum((unsigned char *)ip, sizeof(*ip), 0)); - - // UDP header - struct udphdr *udp = (struct udphdr *)(workspace + sizeof(struct iphdr)); - udp->source = htons(sport); - udp->dest = htons(dport); - udp->len = htons(datalen + sizeof(struct udphdr)); - udp->check = 0; - - int sum = checksum((unsigned char *)&ip->saddr, 2 * sizeof(ip->saddr), IPPROTO_UDP + ntohs(udp->len)); - sum = checksum((unsigned char *)pkt, datalen, sum); - sum = checksum((unsigned char *)udp, sizeof(*udp), sum); - udp->check = wrapsum(sum); - - // Data - memcpy(workspace + sizeof(struct iphdr) + sizeof(struct udphdr), - pkt, datalen); - - // Send out the packet physically - struct sockaddr_in to; - to.sin_family = AF_INET; - to.sin_addr.s_addr = inet_addr(to_ip); - to.sin_port = htons(dport); - - sendto(sock, workspace, ntohs(ip->tot_len), 0, (struct sockaddr *)&to, sizeof(to)); - } - } -} diff --git a/mbd/survey.pl b/mbd/survey.pl deleted file mode 100644 index be33038..0000000 --- a/mbd/survey.pl +++ /dev/null @@ -1,10 +0,0 @@ -package Config; - -our $survey_ip = "176.110.125.15"; -our $survey_port_low = 60100; -our $survey_port_high = 60200; -our $survey_freq = 60.0; -our $survey_time = 10.0; - -1; - |