# Cafe Server v0.2 # Ryan Verner # 19 NOV 2002 # # Thanks to Asx / irc.freenode.net for much help and sample # code. # # TODO: # - encryption, hash possibly based on IP of client machine # with a crypt understood by this server # - verifying that the username reported to this is in fact # valid to a recent login (samba logs?) # DATA WATCHING ON NAT.... # WHEN CLIENT QUITS MANUALLY, NAT IS DISABLED FOR THAT IP require 'socket' require 'mysql' Thread.abort_on_exception = true class ClientQuitError < RuntimeError; end port = ARGV.shift || 9999 host = ARGV.shift || '10.12.0.1' m = Mysql.new('localhost', '*****', '********', '*****') server = TCPServer.open(host, port) port = server.addr[1] addrs = server.addr[2..-1].uniq() puts %!*** Listening on #{addrs.collect{|a|"#{a}:#{port}"}.join(' ')}! def does_user_exist(m, x) res = m.query("select * from users where username='" + x + "'") fields = res.fetch_fields.collect do |f| f.name end x_user = nil res.each do |row| x_user = row.join("\t") end return x_user end def get_remaining(m, x, table) res = m.query("select x_remaining_" + table + " from users where username='" + x + "'") fields = res.fetch_fields.collect do |f| f.name end x_time = nil res.each do |row| x_time = row.join("\t") end return x_time end def unlim(m, x) res = m.query("select x_unlim_acct from users where username='" + x + "'") fields = res.fetch_fields.collect do |f| f.name end x_unlim = nil res.each do |row| x_unlim = row.join("\t") end return x_unlim end def subtract(var, amount) return (var.to_i - amount).to_s end def update_newinfo(m, x, table, user) m.query("update users set x_remaining_" + table + "='" + x + "'" + " where username='" + user + "'") end def delete_user(m, user) m.query("delete from users where username='" + user + "'") end def nat_enable(ip) puts "*** Adding NAT iptables line for " + ip system("iptables -t nat -D POSTROUTING -s " + ip + " -o eth0 -j MASQUERADE") system("iptables -t nat -A POSTROUTING -s " + ip + " -o eth0 -j MASQUERADE") end def nat_disable(ip) puts "*** Removing NAT iptables line for " + ip system("iptables -t nat -D POSTROUTING -s " + ip + " -o eth0 -j MASQUERADE") end loop do socket = server.accept() Thread.start do # one thread per client s = socket port = s.peeraddr[1] name = s.peeraddr[2] addr = s.peeraddr[3] puts "*** Connection from #{name}:#{port}" nat_enable(name) begin while line = s.gets() # read a line at a time raise ClientQuitError if line =~ /^die\r?$/ if does_user_exist(m, line) != nil # skip main stuff if user doesnt exist if unlim(m, line) != "1" # skip main stuff if unlimited account remaining_time = get_remaining(m, line, "time") if remaining_time != nil s.send(remaining_time + "\n", 0) end remaining_data = get_remaining(m, line, "data") if remaining_data != nil s.send(remaining_data + "\n", 0) end puts "#{addr} [#{Time.now}]: #{line.chop} (#{remaining_time} mins, #{remaining_data} mb left)" new_time = subtract(remaining_time, 1) new_data = subtract(remaining_data, 0.5) update_newinfo(m, new_time, "time", line) #update_newinfo(m, new_data, "data", line) if new_time < "0" delete_user(m, line) raise ClientQuitError end if new_data < "0" delete_user(m, line) raise ClientQuitError end end end end rescue ClientQuitError puts "*** #{name}:#{port} Disconnected at [#{Time.now}]" nat_disable(name) ensure s.close() # close socket on error end end end