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:
@@ -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
@@ -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
@@ -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
@@ -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 ""
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user