1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-07-01 17:26:38 +02:00

Protection against linking race conditions is back again (IOTW: allow very rapid re-linking), but only if your network is fully 3.4.x (actually: current git unreal34 or later)

Re-implemented PROTOCTL SERVERS= which nenolod ripped out (#4355).
Add 2nd argument to PROTOCTL EAUTH=servername,unrealprotocol
Change UnrealProtocol from 2350 to 2351
This commit is contained in:
Bram Matthys
2015-07-10 21:57:13 +02:00
parent 5e23fadefb
commit 6c0ebb5bd3
7 changed files with 153 additions and 63 deletions
+2 -1
View File
@@ -2,7 +2,8 @@ VL Information (c) 2002 codemastr (Dominick Meglio) [codemastr@unrealircd.com]
Protocol Version
------------------------------------------------------------------------------------------------
2350 3.4-alpha*
2351 3.4-alpha5
2350 3.4-alpha1/2/3/4
2311 3.2.10
2310 3.2.9
2309 3.2.6, 3.2.7, 3.2.8
+2 -2
View File
@@ -722,9 +722,9 @@ extern char *chfl_to_sjoin_symbol(int s);
extern char chfl_to_chanmode(int s);
extern void add_pending_net(aClient *sptr, char *str);
extern void free_pending_net(aClient *sptr);
extern aPendingNet *find_pending_net_by_numeric_butone(int numeric, aClient *exempt);
extern aClient *find_pending_net_duplicates(aClient *cptr, aClient **srv, int *numeric);
extern aClient *find_non_pending_net_duplicates(aClient *cptr);
extern aPendingNet *find_pending_net_by_sid_butone(char *sid, aClient *exempt);
extern aClient *find_pending_net_duplicates(aClient *cptr, aClient **srv, char **sid);
extern MODVAR char serveropts[];
extern MODVAR char *IsupportStrings[];
extern void finish_auth(aClient *acptr);
+11 -5
View File
@@ -145,7 +145,6 @@ typedef struct _cmdoverride Cmdoverride;
typedef struct SMember Member;
typedef struct SMembership Membership;
typedef struct SMembershipL MembershipL;
typedef struct PendingNet aPendingNet;
#ifdef NEED_U_INT32_T
typedef unsigned int u_int32_t; /* XXX Hope this works! */
@@ -706,6 +705,7 @@ struct Server {
} flags;
struct {
char *chanmodes[4];
int protocol;
} features;
};
@@ -1719,11 +1719,17 @@ struct _parsemode {
char buf[512]; /* internal parse buffer */
};
typedef struct PendingServer aPendingServer;
struct PendingServer {
aPendingServer *prev, *next;
char sid[IDLEN+1];
};
typedef struct PendingNet aPendingNet;
struct PendingNet {
aPendingNet *prev, *next; /* Previous and next in list */
aClient *sptr; /**< Client to which these servers belong */
int numservers; /**< Amount of servers in list */
int servers[1]; /** The list of servers (array of integer server numerics) */
aPendingNet *prev, *next; /* Previous and next in list */
aClient *sptr; /**< Client to which these servers belong */
aPendingServer *servers; /**< The list of servers connected to the client */
};
void init_throttling_hash();
+1 -1
View File
@@ -56,7 +56,7 @@
*/
#define UNREAL_VERSION_TIME 201411
#define UnrealProtocol 2350
#define UnrealProtocol 2351
#define PATCH1 macro_to_str(UNREAL_VERSION_GENERATION)
#define PATCH2 "." macro_to_str(UNREAL_VERSION_MAJOR)
#define PATCH3 ""
+53 -1
View File
@@ -316,6 +316,7 @@ CMD_FUNC(m_protoctl)
{
/* Early authorization: EAUTH=servername[,options] */
int ret;
int protocol = 0;
char *servername = s+6, *p;
ConfigItem_link *aconf = NULL;
@@ -326,8 +327,15 @@ CMD_FUNC(m_protoctl)
{
if (*p == ',')
{
/* Upwards compatible, if we ever add any options through EAUTH=blah,options */
char *x;
*p = '\0';
/* upwards compatible */
x = strchr(p+1, ',');
if (x)
*x = '\0';
protocol = atoi(p+1);
break;
}
if (*p <= ' ' || *p > '~')
@@ -351,9 +359,53 @@ CMD_FUNC(m_protoctl)
SetEAuth(cptr);
make_server(cptr); /* allocate and set cptr->serv */
cptr->serv->features.protocol = protocol;
if (!IsHandshake(cptr) && aconf) /* Send PASS early... */
sendto_one(sptr, "PASS :%s", (aconf->auth->type == AUTHTYPE_PLAINTEXT) ? aconf->auth->data : "*");
}
else if ((strncmp(s, "SERVERS=", 8) == 0) && NEW_LINKING_PROTOCOL)
{
aClient *acptr, *srv;
char *sid = NULL;
if (!IsEAuth(cptr))
continue;
if (cptr->serv->features.protocol < 2351)
continue; /* old SERVERS= version */
/* Other side lets us know which servers are behind it.
* SERVERS=<sid-of-server-1>[,<sid-of-server-2[,..etc..]]
* Eg: SERVER=001,002,0AB,004,005
*/
add_pending_net(sptr, s+8);
acptr = find_non_pending_net_duplicates(sptr);
if (acptr)
{
sendto_one(sptr, "ERROR :Server with SID %s (%s) already exists",
acptr->id, acptr->name);
sendto_realops("Link %s cancelled, server with SID %s (%s) already exists",
get_client_name(acptr, TRUE), acptr->id, acptr->name);
return exit_client(sptr, sptr, sptr, "Server Exists (or non-unique me::sid)");
}
acptr = find_pending_net_duplicates(sptr, &srv, &sid);
if (acptr)
{
sendto_one(sptr, "ERROR :Server with SID %s is being introduced by another server as well. "
"Just wait a moment for it to synchronize...", sid);
sendto_realops("Link %s cancelled, server would introduce server with SID %s, which "
"server %s is also about to introduce. Just wait a moment for it to synchronize...",
get_client_name(acptr, TRUE), sid, get_client_name(srv, TRUE));
return exit_client(sptr, sptr, sptr, "Server Exists (just wait a moment)");
}
/* Send our PROTOCTL SERVERS= back if this was NOT a response */
if (s[8] != '*')
send_protoctl_servers(sptr, 1);
}
else if ((strncmp(s, "TS=",3) == 0) && (IsServer(sptr) || IsEAuth(sptr)))
{
long t = atol(s+3);
+16 -5
View File
@@ -98,15 +98,26 @@ int m_server_synch(aClient *cptr, ConfigItem_link *conf);
*/
void _send_protoctl_servers(aClient *sptr, int response)
{
Link *lp;
char buf[512];
char buf[512];
aClient *acptr;
if (!NEW_LINKING_PROTOCOL)
return;
// TODO: reintroduce SERVERS=...
ircsnprintf(buf, sizeof(buf), "PROTOCTL EAUTH=%s",
me.name);
ircsnprintf(buf, sizeof(buf), "PROTOCTL EAUTH=%s,%d SERVERS=%s",
me.name, UnrealProtocol, response ? "*" : "");
list_for_each_entry(acptr, &global_server_list, client_node)
{
if (*acptr->id)
snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s,", acptr->id);
if (strlen(buf) > sizeof(buf)-12)
break; /* prevent overflow/cutoff if you have a network with more than 90 servers or something. */
}
/* Remove final comma (if any) */
if (buf[strlen(buf)-1] == ',')
buf[strlen(buf)-1] = '\0';
sendto_one(sptr, "%s", buf);
}
+68 -48
View File
@@ -1264,98 +1264,95 @@ aPendingNet *pendingnet = NULL;
void add_pending_net(aClient *sptr, char *str)
{
aPendingNet *e = NULL;
int num = 1;
char *p, *name;
aPendingNet *net;
aPendingServer *srv;
int num = 1;
char *p, *name;
if (BadPtr(str) || !sptr)
return;
/* First, count them */
for (p = str; *p; p++)
if (*p == ',')
num++;
/* Allocate */
e = MyMallocEx(sizeof(aPendingNet) + (sizeof(int) * num));
e->numservers = num;
e->sptr = sptr;
net = MyMallocEx(sizeof(aPendingNet));
net->sptr = sptr;
/* Fill in */
num = 0;
for (name = strtoken(&p, str, ","); name; name = strtoken(&p, NULL, ","))
{
if (!*name)
continue;
/* skip any non-digit prefixes, if necessary. Possibly needed in the future. */
while (*name && !isdigit(*name))
name++;
e->servers[num++] = atoi(name);
srv = MyMallocEx(sizeof(aPendingServer));
strlcpy(srv->sid, name, sizeof(srv->sid));
AddListItem(srv, net->servers);
}
AddListItem(e, pendingnet);
AddListItem(net, pendingnet);
}
void free_pending_net(aClient *sptr)
{
aPendingNet *e, *e_next;
for (e = pendingnet; e; e = e_next)
aPendingNet *net, *net_next;
aPendingServer *srv, *srv_next;
for (net = pendingnet; net; net = net_next)
{
e_next = e->next;
if (e->sptr == sptr)
net_next = net->next;
if (net->sptr == sptr)
{
DelListItem(e, pendingnet);
MyFree(e);
for (srv = net->servers; srv; srv = srv_next)
{
srv_next = srv->next;
MyFree(srv);
}
DelListItem(net, pendingnet);
MyFree(net);
/* Don't break, there can be multiple objects */
}
}
}
aPendingNet *find_pending_net_by_numeric_butone(int numeric, aClient *exempt)
aPendingNet *find_pending_net_by_sid_butone(char *sid, aClient *exempt)
{
aPendingNet *e;
int i;
aPendingNet *net;
aPendingServer *srv;
if (numeric <= 0)
if (BadPtr(sid))
return NULL;
for (e = pendingnet; e; e = e->next)
for (net = pendingnet; net; net = net->next)
{
if (e->sptr == exempt)
if (net->sptr == exempt)
continue;
for (i = 0; i < e->numservers; i++)
if (e->servers[i] == numeric)
return e;
for (srv = net->servers; srv; srv = srv->next)
if (!strcmp(srv->sid, sid))
return net;
}
return NULL;
}
/** Search the pending connections list for any identical numerics */
aClient *find_pending_net_duplicates(aClient *cptr, aClient **srv, int *numeric)
/** Search the pending connections list for any identical sids */
aClient *find_pending_net_duplicates(aClient *cptr, aClient **srv, char **sid)
{
aPendingNet *e, *other;
int i;
aPendingNet *net, *other;
aPendingServer *s;
*srv = NULL;
*numeric = 0;
*sid = NULL;
for (e = pendingnet; e; e = e->next)
for (net = pendingnet; net; net = net->next)
{
if (e->sptr != cptr)
if (net->sptr != cptr)
continue;
/* Ok, found myself */
for (i = 0; i < e->numservers; i++)
for (s = net->servers; s; s = s->next)
{
int curr_numeric = e->servers[i];
other = find_pending_net_by_numeric_butone(curr_numeric, cptr);
char *curr_sid = s->sid;
other = find_pending_net_by_sid_butone(curr_sid, cptr);
if (other)
{
*srv = e->sptr;
*numeric = curr_numeric;
*srv = net->sptr;
*sid = s->sid;
return other->sptr; /* Found another (pending) server with identical numeric */
}
}
@@ -1363,3 +1360,26 @@ int i;
return NULL;
}
aClient *find_non_pending_net_duplicates(aClient *cptr)
{
aPendingNet *net;
aPendingServer *s;
aClient *acptr;
for (net = pendingnet; net; net = net->next)
{
if (net->sptr != cptr)
continue;
/* Ok, found myself */
for (s = net->servers; s; s = s->next)
{
acptr = find_server(s->sid, NULL);
if (acptr)
return acptr; /* Found another (fully CONNECTED) server with identical numeric */
}
}
return NULL;
}