| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- # ArmaBE - Perl extension BattlEye ARMA Rcon interface
- # Original Source for BattlEye source - https://github.com/Jaegerhaus/BE-RCon-Tools
- #
- # $Id:$
- #
- package ArmaBE;
- use strict;
- use warnings;
- use IO::Socket::INET;
- # release version
- our $VERSION = "0.01";
- # create class
- sub new {
- my $class = shift;
- # create object with defaults
- my $self = {
- hostname => undef,
- port => 27015,
- password => undef,
- timeout => 5,
- connected => 0,
- authenticated => 0,
- socket => undef,
- sequence => 0,
- };
- # create object
- bless($self, $class);
- # initialize class instances
- $self->init();
- # parse constructor args
- while (my ($key, $val) = splice(@_, 0, 2)) {
- $key = lc($key);
- if ($key eq "hostname") { $self->hostname($val) }
- elsif ($key eq "port") { $self->port($val) }
- elsif ($key eq "password") { $self->password($val) }
- elsif ($key eq "timeout") { $self->timeout($val) }
- else { print STDERR "Unknown attribute: $key\n" }
- }
- return $self;
- }
- # initialize class instances
- sub init {
- my $self = shift;
- my $class = ref($self);
- # manipulate symbol table.. gotta love perl
- no strict "refs";
- no warnings;
- foreach my $instance (keys %$self) {
- *{"${class}::${instance}"} = sub {
- my $self = shift;
- my $value = shift;
- my $ref = \$self->{$instance};
- if (defined $value) {
- $$ref = $value;
- return $self;
- } else {
- return $$ref;
- }
- };
- }
- }
- # run a command and return its response
- sub run {
- my $self = shift;
- my $command = shift;
- if (!$self->connected()) {
- $self->connect();
- }
- if (!$self->authenticated()) {
- $self->authenticate();
- }
- if ($self->authenticated()) {
- my $socket = $self->socket();
- print $socket $self->packet("\1\0".$command);
- return 1;
- } else {
- return 0;
- }
- }
- # create tcp socket
- sub connect {
- my $self = shift;
- my $socket = IO::Socket::INET->new(
- PeerAddr => $self->hostname(),
- PeerPort => $self->port(),
- Timeout => $self->timeout(),
- Proto => "udp",
- ) || die "Failed to connect: $!\n";
- $self->socket($socket);
- $self->connected(1);
- }
- # authenticate rcon session
- sub authenticate {
- my $self = shift;
- # send authentication packet to server
- my $socket = $self->socket();
- print $socket $self->packet("\0".$self->password());
- my $response = $self->response();
- my $authenticated = int(substr($response, -1));
- $self->authenticated($authenticated);
- }
- ######################
- # PROTOCOL FUNCTIONS #
- ######################
- # rcon command protocol:
- # https://www.battleye.com/downloads/BERConProtocol.txt
- sub crc32 {
- my ($self,$input,$init_value,$polynomial) = @_;
- $init_value = 0 unless (defined $init_value);
- $polynomial = 0xedb88320 unless (defined $polynomial);
- my @lookup_table;
- for (my $i=0; $i<256; $i++) {
- my $x = $i;
- for (my $j=0; $j<8; $j++) {
- if ($x & 1) {
- $x = ($x >> 1) ^ $polynomial;
- } else {
- $x = $x >> 1;
- }
- }
- push @lookup_table, $x;
- }
- my $crc = $init_value ^ 0xffffffff;
- foreach my $x (unpack ('C*', $input)) {
- $crc = (($crc >> 8) & 0xffffff) ^ $lookup_table[ ($crc ^ $x) & 0xff ];
- }
- $crc = $crc ^ 0xffffffff;
- return $crc;
- }
- # create a packet of type (AUTH or CMD)
- sub packet {
- my $self = shift;
- my $payload = shift;
- my $break = pack('C', 0xff);
- my $packet = "BE"
- . pack('V', $self->crc32($break . $payload))
- . $break
- . $payload;
- return $packet;
- }
- # receive packet
- sub response {
- my $self = shift;
- my $payload = $self->read();
- return $payload;
- }
- # read length of bytes from socket with timeout
- sub read {
- my $self = shift;
- my $received;
- my $socket = $self->socket();
-
- $socket->recv($received, 9);
- return unpack('H*', $received);
- }
- 1;
- __END__
|