87 lines
2.5 KiB
Ruby
87 lines
2.5 KiB
Ruby
module NSCA
|
|
class Server
|
|
include Enumerable
|
|
|
|
attr_reader :iv_key, :server, :packet_version, :password, :xor_iv_key, :xor_password
|
|
def initialize *args
|
|
opts = {}
|
|
opts = args.pop.dup if args.last.is_a? Hash
|
|
opts[:host] ||= opts[:hostname]
|
|
opts[:serv] ||= opts[:server]
|
|
opts[:pass] ||= opts[:password]
|
|
|
|
case args[0]
|
|
when Integer
|
|
opts[:port] = args[0]
|
|
opts[:host] ||= args[1]
|
|
when IO
|
|
opts[:serv] = args[0]
|
|
end
|
|
|
|
@packet_version = opts[:packet_version] || PacketV3
|
|
@iv_key = (opts[:iv_key] || SecureRandom.random_bytes( 128)).to_s
|
|
raise ArgumentError, "Key must be 128 bytes long" unless 128 == @iv_key.length
|
|
@password = opts[:pass].to_s
|
|
@server = if opts[:serv].is_a?( TCPServer) or opts[:serv].is_a?( UNIXServer)
|
|
opts[:serv]
|
|
elsif opts[:port].is_a? Integer
|
|
TCPServer.new *[opts[:host], opts[:port]].compact
|
|
else
|
|
raise ArgumentError, "Server or port-number expected"
|
|
end
|
|
end
|
|
|
|
def accept() Connection.new @server.accept, self end
|
|
def close() @server.close end
|
|
|
|
def each &block
|
|
return Enumerator.new( self) unless block_given?
|
|
while conn = accept
|
|
yield conn
|
|
end
|
|
end
|
|
|
|
class Connection
|
|
include Enumerable
|
|
|
|
def initialize socket, server
|
|
@socket, @server = socket, server
|
|
@iv_key, @password = server.iv_key, server.password
|
|
@packet_version = server.packet_version
|
|
@packet_length = @packet_version::PACK_LENGTH
|
|
@socket.write [@iv_key, Time.now.to_i].pack( 'a* L>')
|
|
@xor_password = NSCA::Helper.xor_stream @password
|
|
@xor_iv_key = NSCA::Helper.xor_stream @iv_key
|
|
end
|
|
|
|
def fetch
|
|
iv_key = NSCA::Helper.xor_stream @iv_key
|
|
password = NSCA::Helper.xor_stream @password
|
|
packet_version = iv_key[ password[ read PacketV3::PACKET_VERSION]]
|
|
v = packet_version.unpack( 's>').first
|
|
case v
|
|
when 3
|
|
data = packet_version + iv_key[ password[ read( PacketV3::PACK_LENGTH - PacketV3::PACKET_VERSION)]]
|
|
begin
|
|
return PacketV3.parse( data)
|
|
rescue NSCA::Packet::CSC32CheckFailed
|
|
x = read( PacketV3__2_9::PACK_LENGTH - data.length)
|
|
raise if x.nil?
|
|
return PacketV3__2_9.parse( data + iv_key[ password[ x]])
|
|
end
|
|
else raise "Unknown Version #{v.inspect}"
|
|
end
|
|
end
|
|
|
|
def each &block
|
|
return Enumerator.new( self) unless block_given?
|
|
yield fetch until eof?
|
|
end
|
|
|
|
def eof?() @socket.eof? end
|
|
def read( len = nil) @socket.read( len || @packet_length) end
|
|
def close() @socket.close end
|
|
end
|
|
end
|
|
end
|