summaryrefslogtreecommitdiff
path: root/src/modules/m_spanningtree/nickcollide.cpp
blob: 5d36bc46f4e74c6be267b0495e71c776d0967879 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*       +------------------------------------+
 *       | Inspire Internet Relay Chat Daemon |
 *       +------------------------------------+
 *
 *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
 * See: http://www.inspircd.org/wiki/index.php/Credits
 *
 * This program is free but copyrighted software; see
 *            the file COPYING for details.
 *
 * ---------------------------------------------------
 */

#include "inspircd.h"
#include "commands/cmd_whois.h"
#include "commands/cmd_stats.h"
#include "socket.h"
#include "wildcard.h"
#include "xline.h"
#include "transport.h"
#include "m_hash.h"
#include "socketengine.h"

#include "m_spanningtree/main.h"
#include "m_spanningtree/utils.h"
#include "m_spanningtree/treeserver.h"
#include "m_spanningtree/link.h"
#include "m_spanningtree/treesocket.h"
#include "m_spanningtree/resolvers.h"
#include "m_spanningtree/handshaketimer.h"

/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_hash.h */

/*
 * Yes, this function looks a little ugly.
 * However, in some circumstances we may not have a User, so we need to do things this way.
 * Returns 1 if colliding local client, 2 if colliding remote, 3 if colliding both.
 * Sends SVSNICKs as appropriate and forces nickchanges too.
 */
int TreeSocket::DoCollision(User *u, time_t remotets, const char *remoteident, const char *remoteip, const char *remoteuid)
{
	/*
	 *  Under old protocol rules, we would have had to kill both clients.
	 *  Really, this sucks.
	 * These days, we have UID. And, so what we do is, force nick change client(s)
	 * involved according to timestamp rules.
	 *
	 * RULES: 	 
	 *  user@ip equal: 	 
	 *   Force nick change on OLDER timestamped client 	 
	 *  user@ip differ: 	 
	 *   Force nick change on NEWER timestamped client 	 
	 *  TS EQUAL: 	 
	 *   FNC both. 	 
	 * 	 
	 * This stops abusive use of collisions, simplifies problems with loops, and so on. 	 
	 *   -- w00t
	 */
	bool bChangeLocal = true;
	bool bChangeRemote = true;

	/* for brevity, don't use the User */
	time_t localts = u->age;
	const char *localident = u->ident;
	const char *localip = u->GetIPString();

	/* mmk. let's do this again. */
	if (remotets == localts)
	{
		/* equal. fuck them both! do nada, let the handler at the bottom figure this out. */
	}
	else
	{
		/* fuck. now it gets complex. */

		/* first, let's see if ident@host matches. */
		bool SamePerson = !strcmp(localident, remoteident)
				&& !strcmp(localip, remoteip);

		/*
		 * if ident@ip is equal, and theirs is newer, or
		 * ident@ip differ, and ours is newer
		 */
		if((SamePerson && remotets < localts) ||
		   (!SamePerson && remotets > localts))
		{
			/* remote needs to change */
			bChangeLocal = false;
		}
		else
		{
			/* ours needs to change */
			bChangeRemote = false;
		}
	}


	if (bChangeLocal)
	{
		u->ForceNickChange(u->uuid);

		if (!bChangeRemote)
			return 1;
	}
	if (bChangeRemote)
	{
		/*
		 * Cheat a little here. Instead of a dedicated command to change UID,
		 * use SVSNICK and accept their client with it's UID (as we know the SVSNICK will
		 * not fail under any circumstances -- UIDs are netwide exclusive).
		 *
		 * This means that each side of a collide will generate one extra NICK back to where
		 * they have just linked (and where it got the SVSNICK from), however, it will
		 * be dropped harmlessly as it will come in as :928AAAB NICK 928AAAB, and we already
		 * have 928AAAB's nick set to that.
		 *   -- w00t
		 */
		User *remote = this->Instance->FindUUID(remoteuid);

		if (remote)
		{
			/* buh.. nick change collide. force change their nick. */
			remote->ForceNickChange(remote->uuid);
		}
		else
		{
			/* user has not been introduced yet, just inform their server */
			this->WriteLine(std::string(":")+this->Instance->Config->GetSID()+" SVSNICK "+remoteuid+" " + remoteuid + " " + ConvToStr(remotets));
		}

		if (!bChangeLocal)
			return 2;
	}

	return 3;
}