News:

Simutrans.com Portal
Our Simutrans site. You can find everything about Simutrans from here.

[patch] network play: log ip of clients

Started by Dwachs, December 02, 2012, 08:25:41 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Dwachs

This patch enables logging of ip/nickname of clients that created a company and that played for a company. These information can be retrieved by nettool with new command 'companies'.

Any comments and suggestions how to proceed with these stuff ?

Next  steps could be unlocking and removing of companies via nettool.
Parsley, sage, rosemary, and maggikraut.

kierongreen

Excellent. Those sound like sensible further steps - maybe also option to liquidate?

Ashley

Looks good! Options to unlock (or, indeed, lock e.g. change password), remove/liquidate and rename companies would be very useful.
Use Firefox? Interested in IPv6? Try SixOrNot the IPv6 status indicator for Firefox.
Why not try playing Simutrans online? See the Game Servers board for details.

greenling

Index: simversion.h
===================================================================
--- simversion.h (revision 6126)
+++ simversion.h (working copy)
@@ -18,7 +18,7 @@
// Beware: SAVEGAME minor is often ahead of version minor when there were patches.
// ==> These have no direct connection at all!
#define SIM_SAVE_MINOR      0
-#define SIM_SERVER_MINOR    0
+#define SIM_SERVER_MINOR    1

#define MAKEOBJ_VERSION "55"

Index: simworld.cc
===================================================================
--- simworld.cc (revision 6126)
+++ simworld.cc (working copy)
@@ -2454,6 +2454,10 @@
if ( (param != spieler_t::HUMAN  &&  !public_player_unlocked)  ||  param >= spieler_t::MAX_AI) {
return false;
}
+ // range check, player already existent?
+ if ( player_nr >= PLAYER_UNOWNED  ||   get_spieler(player_nr) ) {
+ return false;
+ }
if (exec) {
new_spieler( player_nr, param );
// activate/deactivate AI immediately
Index: tpl/vector_tpl.h
===================================================================
--- tpl/vector_tpl.h (revision 6126)
+++ tpl/vector_tpl.h (working copy)
@@ -160,15 +160,18 @@
while(  high - low>1  ) {
const sint32 mid = ((uint32) (low + high)) >> 1;
T &mid_elem = data[mid];
- if(  elem==mid_elem  ) {
- return &mid_elem;
- }
- else if(  comp(elem, mid_elem)  ) {
+ if(  comp(elem, mid_elem)  ) {
+ // elem < mid_elem
high = mid;
}
- else {
+ else if(  comp(mid_elem, elem)  ) {
+ // mid_elem < elem
low = mid;
}
+ else {
+ // mid_elem == elem
+ return &mid_elem;
+ }
}
insert_at(high, elem);
return NULL;
Index: dataobj/network_socket_list.cc
===================================================================
--- dataobj/network_socket_list.cc (revision 6126)
+++ dataobj/network_socket_list.cc (working copy)
@@ -8,6 +8,16 @@
#endif


+bool connection_info_t::compare(connection_info_t const* a, connection_info_t const* b)
+{
+ sint64 diff = (sint64)a->address.get_ip() - (sint64)b->address.get_ip();
+ if (diff == 0) {
+ diff = strcmp(a->nickname.c_str(), b->nickname.c_str());
+ }
+ return diff < 0;
+}
+
+
void socket_info_t::reset()
{
if (packet) {
@@ -212,11 +222,11 @@
#ifndef NETTOOL
// set server nickname
if (!umgebung_t::nickname.empty()) {
- list[i]->nickname = umgebung_t::nickname;
+ list[i]->nickname = umgebung_t::nickname.c_str();
}
else {
list[i]->nickname = "Server#0";
- umgebung_t::nickname = list[i]->nickname;
+ umgebung_t::nickname = list[i]->nickname.c_str();
}
#endif //NETTOOL
}
Index: dataobj/network_cmd_ingame.h
===================================================================
--- dataobj/network_cmd_ingame.h (revision 6126)
+++ dataobj/network_cmd_ingame.h (working copy)
@@ -9,6 +9,7 @@
#include "koord3d.h"

class memory_rw_t;
+class connection_info_t;
class packet_t;
class spieler_t;
class werkzeug_t;
@@ -305,6 +306,15 @@
uint8 cmd;
uint8 player_nr;
uint16 param;
+
+ /// store information about client that tries to create a company
+ static connection_info_t* pending_company_creator[PLAYER_UNOWNED];
+
+ /// store information about client that created a company
+ static connection_info_t* company_creator[PLAYER_UNOWNED];
+
+ /// store information about clients that played with a company
+ static vector_tpl<connection_info_t*> company_active_clients[PLAYER_UNOWNED];
};

/**
Index: dataobj/network_address.cc
===================================================================
--- dataobj/network_address.cc (revision 6126)
+++ dataobj/network_address.cc (working copy)
@@ -34,10 +34,12 @@
}


-void net_address_t::rdwr(packet_t *packet)
+net_address_t::net_address_t(const net_address_t &other)
{
- packet->rdwr_long(ip);
- packet->rdwr_long(mask);
+ ip = other.ip;
+ mask = other.mask;
+ ipstr[0] = '\0';
+ init_ipstr();
}


Index: dataobj/network_cmd.cc
===================================================================
--- dataobj/network_cmd.cc (revision 6126)
+++ dataobj/network_cmd.cc (working copy)
@@ -121,6 +121,7 @@
case SRVC_BAN_IP:
case SRVC_UNBAN_IP:
case SRVC_ADMIN_MSG:
+ case SRVC_GET_COMPANY_LIST:
packet->rdwr_str(text);
break;

Index: dataobj/network_cmd_ingame.cc
===================================================================
--- dataobj/network_cmd_ingame.cc (revision 6126)
+++ dataobj/network_cmd_ingame.cc (working copy)
@@ -843,6 +843,27 @@
}
socket_info_t const& info = socket_list_t::get_client(our_client_id); //.is_player_unlocked(player_nr)

+ if (!welt->change_player_tool(cmd, player_nr, param, info.is_player_unlocked(1), false)) {
+ return NULL;
+ }
+
+ // only one company creation per client IP allowed
+ if (cmd == karte_t::new_player  &&  player_nr < lengthof(pending_company_creator)) {
+ if ( our_client_id != 0) {
+ for(uint8 i = 2; i<lengthof(company_creator); i++) {
+ if (company_creator[i]  &&  info.address == company_creator[i]->address) {
+ // this client already created a company
+ //return NULL;
+ }
+ }
+ }
+ // temporary store address of client
+ delete pending_company_creator[player_nr];
+
+ dbg->warning("nwc_chg_player_t::clone", "pending_company_creator for %d is set to %s/%s", player_nr, info.address.get_str(), info.nickname.c_str());
+ pending_company_creator[player_nr] = new connection_info_t( info );
+ }
+
if (welt->change_player_tool(cmd, player_nr, param, info.is_player_unlocked(1), false)) {
return new nwc_chg_player_t(get_sync_step(), get_map_counter(), cmd, player_nr, param);
}
@@ -850,10 +871,30 @@
}


+connection_info_t* nwc_chg_player_t::pending_company_creator[PLAYER_UNOWNED] = {
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
+
+connection_info_t* nwc_chg_player_t::company_creator[PLAYER_UNOWNED] = {
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
+
+vector_tpl<connection_info_t*> nwc_chg_player_t::company_active_clients[PLAYER_UNOWNED];
+
+
void nwc_chg_player_t::do_command(karte_t *welt)
{
welt->change_player_tool(cmd, player_nr, param, true, true);

+ // store IP of client who created this company
+ if (umgebung_t::server  &&   cmd == karte_t::new_player  &&  player_nr < lengthof(pending_company_creator)) {
+ company_creator[player_nr] =  pending_company_creator[player_nr];
+
+ if (pending_company_creator[player_nr]) {
+ dbg->warning("nwc_chg_player_t::clone", "company_creator for %d is set to %s/%s", player_nr,
+ pending_company_creator[player_nr]->address.get_str(), pending_company_creator[player_nr]->nickname.c_str());
+ }
+ pending_company_creator[player_nr] = NULL;
+ }
+
// update the window
ki_kontroll_t* playerwin = (ki_kontroll_t*)win_get_magic(magic_ki_kontroll_t);
if (playerwin) {
@@ -987,7 +1028,8 @@
player_nr = 1;
default: ;
}
- if ( player_nr < PLAYER_UNOWNED  &&  !socket_list_t::get_client(our_client_id).is_player_unlocked(player_nr) ) {
+ socket_info_t const& info = socket_list_t::get_client(our_client_id);
+ if ( player_nr < PLAYER_UNOWNED  &&  !info.is_player_unlocked(player_nr) ) {
if (wkz_id == (WKZ_ADD_MESSAGE_TOOL|SIMPLE_TOOL)) {
player_nr = PLAYER_UNOWNED;
}
@@ -996,6 +1038,14 @@
return NULL; // indicate failure
}
}
+ // log that this client acted as this player
+ if (player_nr < PLAYER_UNOWNED) {
+ connection_info_t *cinfo = new connection_info_t(info);
+ if(nwc_chg_player_t::company_active_clients[player_nr].insert_unique_ordered(cinfo, connection_info_t::compare) != NULL) {
+ delete cinfo; // entry exists already
+ }
+ }
+
// do scenario checks here, send error message back
scenario_t *scen = welt->get_scenario();
if ( scen->is_scripted() ) {
@@ -1326,6 +1376,41 @@
break;
}

+ case SRVC_GET_COMPANY_LIST: {
+ cbuffer_t buf;
+ for (uint8 i=0; i<PLAYER_UNOWNED; i++) {
+ if (spieler_t *sp = welt->get_spieler(i)) {
+ buf.printf("Company #%d: %s\n", i, sp->get_name());
+ buf.printf("    Password: %sset\n", sp->access_password_hash().empty() ? "NOT " :"");
+ // print creator information
+ if (i < lengthof(nwc_chg_player_t::company_creator)) {
+ if (connection_info_t const* creator = nwc_chg_player_t::company_creator[i]) {
+ buf.printf("    founded by  %s at %s\n", creator->nickname.c_str(), creator->address.get_str());
+ }
+ }
+ // print clients who have this player unlocked
+ for(uint32 j = 0; j < socket_list_t::get_count(); j++) {
+ socket_info_t const& info = socket_list_t::get_client(j);
+ if (info.is_active()  &&  info.is_player_unlocked(i)) {
+ buf.printf("    unlocked by [%d] %s at %s\n", j, info.nickname.c_str(), info.address.get_str());
+ }
+ }
+ // print clients who played for this company
+ for(uint32 j = 0; j < nwc_chg_player_t::company_active_clients[i].get_count(); j++) {
+ connection_info_t const* info = nwc_chg_player_t::company_active_clients[i][j];
+ if (info) {
+ buf.printf("    played   by [%d] %s at %s\n", j, info->nickname.c_str(), info->address.get_str());
+ }
+ }
+ }
+ }
+
+ nwc_service_t nws;
+ nws.flag = SRVC_GET_COMPANY_LIST;
+ nws.text = strdup(buf);
+ nws.send(packet->get_sender());
+ }
+
default: ;
}
return true; // to delete
Index: dataobj/network_socket_list.h
===================================================================
--- dataobj/network_socket_list.h (revision 6126)
+++ dataobj/network_socket_list.h (working copy)
@@ -5,12 +5,38 @@
#include "network_address.h"
#include "../tpl/slist_tpl.h"
#include "../tpl/vector_tpl.h"
-#include <string>
+#include "../utils/plainstring.h"

class network_command_t;
class packet_t;

-class socket_info_t {
+
+/**
+ * Class to store pairs of (address, nickname) for logging and admin purposes.
+ */
+class connection_info_t {
+public:
+ /// address of connection
+ net_address_t address;
+
+ /// client nickname
+ plainstring nickname;
+
+ connection_info_t() : address(), nickname() {}
+
+ connection_info_t(const connection_info_t& other) : address(other.address), nickname(other.nickname) {}
+
+ template<class F> void rdwr(F *packet)
+ {
+ address.rdwr(packet);
+ packet->rdwr_str(nickname);
+ }
+
+ static bool compare(connection_info_t const* a, connection_info_t const* b);
+};
+
+
+class socket_info_t : public connection_info_t {
private:
packet_t *packet;
slist_tpl<packet_t *> send_queue;
@@ -29,12 +55,8 @@

SOCKET socket;

- net_address_t address;
+ socket_info_t() : connection_info_t(), packet(0), send_queue(), state(inactive), socket(INVALID_SOCKET), player_unlocked(0) {}

- std::string nickname;
-
- socket_info_t() : packet(0), send_queue(), state(inactive), socket(INVALID_SOCKET), address(), player_unlocked(0) {}
-
~socket_info_t();

/**
Index: dataobj/network_address.h
===================================================================
--- dataobj/network_address.h (revision 6126)
+++ dataobj/network_address.h (working copy)
@@ -24,11 +24,21 @@

net_address_t(const char *);

+ net_address_t(const net_address_t&);
+
bool matches(const net_address_t &other) const {
return (other.ip & mask)==(ip & mask);
}

- void rdwr(packet_t *packet);
+ template<class F> void rdwr(F *packet)
+ {
+ packet->rdwr_long(ip);
+ packet->rdwr_long(mask);
+ if (packet->is_loading()) {
+ ipstr[0] = '\0';
+ init_ipstr();
+ }
+ }

/**
* Return human readable representation of this IP address
@@ -36,9 +46,11 @@
*/
const char* get_str () const;

- bool operator==(const net_address_t& other) {
+ bool operator==(const net_address_t& other) const {
return ip==other.ip  &&  mask == other.mask;
}
+
+ uint32 get_ip() const { return ip; }
};

class address_list_t : public vector_tpl<net_address_t> {
Index: dataobj/network_cmd.h
===================================================================
--- dataobj/network_cmd.h (revision 6126)
+++ dataobj/network_cmd.h (working copy)
@@ -104,6 +104,7 @@
SRVC_ADMIN_MSG       = 8,
SRVC_SHUTDOWN        = 9,
SRVC_FORCE_SYNC      = 10,
+ SRVC_GET_COMPANY_LIST = 11,
SRVC_MAX
};

Index: nettools/nettool.cc
===================================================================
--- nettools/nettool.cc (revision 6126)
+++ nettools/nettool.cc (working copy)
@@ -101,6 +101,33 @@
return 0;
}

+// Simple command to send command ID to server and receive and print a text buffer
+int simple_gettext_command(SOCKET socket, uint32 command_id, int, char **) {
+ nwc_service_t nwcs;
+ nwcs.flag = command_id;
+ if (!nwcs.send(socket)) {
+ fprintf(stderr, "Could not send request!\n");
+ return 2;
+ }
+ nwc_service_t *nws = (nwc_service_t*)network_receive_command(NWC_SERVICE);
+ if (nws==NULL) {
+ return 3;
+ }
+ if (nws->flag != command_id) {
+ delete nws;
+ return 3;
+ }
+
+ if (nws->text) {
+ printf(nws->text);
+ }
+ else {
+ printf("Nothing received.\n");
+ }
+ delete nws;
+ return 0;
+}
+
int get_client_list(SOCKET socket, uint32 command_id, int, char **) {
nwc_service_t nwcs;
nwcs.flag = command_id;
@@ -291,6 +318,9 @@
"      clients\n"
"        Receive list of playing clients from server\n"
"\n"
+ "      companies\n"
+ "        Receive list of running companies from server\n"
+ "\n"
"      kick-client <client number>\n"
"      ban-client  <client number>\n"
"        Kick / ban client (use clients command to get client number)\n"
@@ -403,6 +433,7 @@
command_t commands[] = {
{"announce",    false, nwc_service_t::SRVC_ANNOUNCE_SERVER, 0, &simple_command},
{"clients",     true,  nwc_service_t::SRVC_GET_CLIENT_LIST, 0, &get_client_list},
+ {"companies",   true,  nwc_service_t::SRVC_GET_COMPANY_LIST, 0, &simple_gettext_command},
{"kick-client", true,  nwc_service_t::SRVC_KICK_CLIENT,     1, &kick_client},
{"ban-client",  true,  nwc_service_t::SRVC_BAN_CLIENT,      1, &ban_client},
{"blacklist",   true,  nwc_service_t::SRVC_GET_BLACK_LIST,  0, &get_blacklist},


It that all in r6127?
Opening hours 20:00 - 23:00
(In Night from friday on saturday and saturday on sunday it possibly that i be keep longer in Forum.)
I am The Assistant from Pakfilearcheologist!
Working on a big Problem!

Dwachs

Parsley, sage, rosemary, and maggikraut.

Dwachs

update: new functionality to nettool:


      companies
        Receive list of running companies from server

      info-company <company number>
        Show detailed info for company

      unlock-company <company number>
        Clears password of company, effectively unlocking it for all clients

      remove-company <company number>
        Immediately remove company and all its belongings

Parsley, sage, rosemary, and maggikraut.

prissi

I thing this is very useful and should be committed.

Ashley

This looks great. I'd like to ask for one more addition, being able to set a company's password using nettool would be useful too (e.g. for setting a password on the public service account).

(Actually being able to change a company's name would be quite useful also...)
Use Firefox? Interested in IPv6? Try SixOrNot the IPv6 status indicator for Firefox.
Why not try playing Simutrans online? See the Game Servers board for details.

Dwachs

Update. Implemented features:

      companies
        Receive list of running companies from server

      info-company <company number>
        Show detailed info for company

      lock-company <company number> <new password>
      lock-company <company number> -F <filename>
        Set password, read from file if specified (use '-' to read from stdin)

      unlock-company <company number>
        Clears password of company, effectively unlocking it for all clients

      remove-company <company number>
        Immediately remove company and all its belongings

Implementing renaming of companies is a lot more complicated, I am afraid.

All these IP / nickname information is not saved, they will be lost after server crash / restart. Is a save/load routine important?

Otherwise, this patch is kind of feature-complete and commit-ready.
Parsley, sage, rosemary, and maggikraut.

Ashley

This looks good, a save/load routine for this data would be ideal given that server crashes/restarts are still not unheard of. But could do without if it's really hard to do.
Use Firefox? Interested in IPv6? Try SixOrNot the IPv6 status indicator for Firefox.
Why not try playing Simutrans online? See the Game Servers board for details.

Dwachs

Parsley, sage, rosemary, and maggikraut.