Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion common/struct_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ typedef enum Status {
#endif
#define IsCloaked(x) ((x)->user && (x)->user->flags & FLAGS_CLOAKED)
#define SetCloaked(x) ((x)->user->flags |= FLAGS_CLOAKED)
#define HAS_CLOAK_IP(x) (!IN6_IS_ADDR_UNSPECIFIED(&((x)->cloak_ip)))
#define IsTLS(x) ((x)->user && (x)->user->flags & FLAGS_TLS)
#define SetTLS(x) ((x)->user->flags |= FLAGS_TLS)
#define IsCAPNegotiation(x) (MyConnect(x) && (x)->cap_negotation)
Expand Down Expand Up @@ -537,7 +538,7 @@ struct Client {
char uid[UIDLEN+1];
u_int uidhashv; /* raw hash value of UID */
aClient *uhnext;
char *sasl_user; /* After successful login, the SASL user name will be stored here */
char *sasl_user; /* After successful login, the SASL username will be stored here */
/*
** The following fields are allocated only for local clients
** (directly connected to *this* server with a socket.
Expand Down Expand Up @@ -567,6 +568,7 @@ struct Client {
char *auth;
u_short port; /* and the remote port# too :-) */
struct IN_ADDR ip; /* keep real ip# too */
struct IN_ADDR cloak_ip; /* cloak ip# */
struct hostent *hostp;
char sockhost[HOSTLEN+1]; /* This is the host name from the socket
** and after which the connection was
Expand Down
4 changes: 2 additions & 2 deletions doc/sasl.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This implementation is based on the documentation from Mantas Mikulėnas. Read *
The following things are different:
* logout is not supported
* abortion of authentication is not supported, the user has to disable SASL explicitly at his IRC client if he wants to connect without authentication
* the L-message contains the cloak (`L <loginName> :<cloak>`) and the ircd sets it after successful authentication
* if the user has configured a cloaked hostname, the L-message contains a unique local IPv6 address and the cloaked hostname (`L <loginName> [<ip> :<hostname>]`)
* the H-message contains a hostmask (`H <nick>[[ident]@ip]`)
* additional N-message to allow the SASL service to send a NOTICE to a user (`N :<notice>`)
* additional K-message to allow the SASL service to disconnect a user before registration (K :<reason>`), e.g. if he fails to log in too often
Expand Down Expand Up @@ -38,7 +38,7 @@ You need to set up at least one service with the flags SERVICE_WANT_SASL and SER
// The server forwards the message to the SASL service
[Server -> Service] :000B SASL 000BAAAAD SASLService@irc1.localhost C dXNlcjEAdXNlcjEAdXNlcjEtcGFzc3dvcmQxMjM=
// The service validates the credentials and sends success messages including the cloaked hostname
[Service -> Server] ENCAP 000B SASL 000BAAAAD * L user1 :spoof1.ircnet.com
[Service -> Server] ENCAP 000B SASL 000BAAAAD * L user1 fdf0:584f:e66b:1::1 :spoof1.ircnet.com
[Service -> Server] ENCAP 000B SASL 000BAAAAD * D S
// The server sets the cloaked hostname and sends a success message to the client
[Server -> User] :irc1.localhost 900 patrick :You are now logged in as user1.
Expand Down
2 changes: 1 addition & 1 deletion ircd/channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ static Link *match_modeid(int type, aClient *cptr, aChannel *chptr)
}
/* so now we check CIDR */
if (strchr(tmp->value.alist->host, '/') &&
match_ipmask_client(tmp->value.alist->host, cptr, 0) == 0)
match_ipmask_client(tmp->value.alist->host, cptr, 0, 1) == 0)
{
break;
}
Expand Down
1 change: 1 addition & 0 deletions ircd/list.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ aClient *make_client(aClient *from)
cptr->caps = 0;
cptr->sasl_service = NULL;
cptr->cloak_tmp = NULL;
memset(&cptr->cloak_ip, 0, sizeof(cptr->cloak_ip));
}
return (cptr);
}
Expand Down
149 changes: 83 additions & 66 deletions ircd/s_conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -450,11 +450,12 @@ void det_confs_butmask(aClient *cptr, int mask)
* Now should work for IPv6 too.
* returns -1 on error, 0 on match, 1 when NO match.
*/
int match_ipmask_client(char *mask, aClient *cptr, int maskwithusername)
int match_ipmask_client(char *mask, aClient *cptr, int maskwithusername, int prefer_cloak)
{
int m;
char *p;
struct IN_ADDR addr;
struct IN_ADDR client_addr = prefer_cloak ? get_client_addr(cptr) : cptr->ip;
char dummy[128];
char *omask;
u_long lmask;
Expand Down Expand Up @@ -500,15 +501,16 @@ int match_ipmask_client(char *mask, aClient *cptr, int maskwithusername)
j = m & 0x1F; /* number not mutliple of 32 bits */
m >>= 5; /* number of 32 bits */

if (m && memcmp((void *)(addr.s6_addr),
(void *)(cptr->ip.s6_addr), m << 2))
if (m && memcmp((void *) (addr.s6_addr),
(void *) (client_addr.s6_addr), m << 2))
return 1;

if (j)
{
lmask = htonl((u_long)0xffffffffL << (32 - j));
if ((((u_int32_t *)(addr.s6_addr))[m] ^
((u_int32_t *)(cptr->ip.s6_addr))[m]) & lmask)
lmask = htonl((u_long) 0xffffffffL << (32 - j));
if ((((u_int32_t *) (addr.s6_addr))[m] ^
((u_int32_t *) (client_addr.s6_addr))[m]) &
lmask)
return 1;
}

Expand All @@ -534,20 +536,50 @@ int attach_Iline(aClient *cptr, struct hostent *hp, char *sockhost)
int retval = -2; /* EXITC_NOILINE in register_user() */

/* We fill uaddr and uhost now, before aconf loop. */
sprintf(uaddr, "%s@%s", cptr->username, sockhost);
if (hp)
if (HAS_CLOAK_IP(cptr) && cptr->cloak_tmp)
{
char fullname[HOSTLEN+1];
// Set IP address
char cloak_ip[HOSTLEN + 1];
inetntop(AF_INET6, (void *) cptr->cloak_ip.s6_addr, cloak_ip, sizeof(cloak_ip));
if (cptr->user->sip)
{
MyFree(cptr->user->sip);
}
cptr->user->sip = mystrdup(cloak_ip);

// Set hostname
strncpyzt(cptr->sockhost, cptr->cloak_tmp, HOSTLEN + 1);
strncpyzt(cptr->user->host, cptr->cloak_tmp, HOSTLEN + 1);
MyFree(cptr->cloak_tmp);
cptr->cloak_tmp = NULL;

// Mark as cloaked
SetCloaked(cptr);

/* If not for add_local_domain, I wouldn't need this
** fullname. Can't we add_local_domain somewhere in
** dns code? --B. */
strncpyzt(fullname, hp->h_name, sizeof(fullname));
add_local_domain(fullname, HOSTLEN - strlen(fullname));
Debug((DEBUG_DNS, "a_il: %s->%s", sockhost, fullname));
sprintf(uhost, "%s@%s", cptr->username, fullname);
// Set variables for I-Line check
sprintf(uaddr, "%s@%s", cptr->username, cptr->user->sip);
sprintf(uhost, "%s@%s", cptr->username, cptr->user->host);
}
else
{
sprintf(uaddr, "%s@%s", cptr->username, sockhost);
if (hp)
{
char fullname[HOSTLEN + 1];

/* If not for add_local_domain, I wouldn't need this
** fullname. Can't we add_local_domain somewhere in
** dns code? --B. */
strncpyzt(fullname, hp->h_name, sizeof(fullname));
add_local_domain(fullname, HOSTLEN - strlen(fullname));
Debug((DEBUG_DNS, "a_il: %s->%s", sockhost, fullname));
sprintf(uhost, "%s@%s", cptr->username, fullname);
}
else
{
uhost[0] = '\0';
}
}
/* all uses of uhost are guarded by if (hp), so no need to zero it. */

for (aconf = conf; aconf; aconf = aconf->next)
{
Expand Down Expand Up @@ -585,7 +617,7 @@ int attach_Iline(aClient *cptr, struct hostent *hp, char *sockhost)
{
int namematched = 0;

if (hp)
if (*uhost)
{
if (!UHConfMatch(aconf->name, uhost, ulen))
{
Expand Down Expand Up @@ -625,7 +657,7 @@ int attach_Iline(aClient *cptr, struct hostent *hp, char *sockhost)

/* match_ipmask_client takes care of checking
** possible username if aconf->host has '@' */
if (match_ipmask_client(aconf->host, cptr, 1))
if (match_ipmask_client(aconf->host, cptr, 1, 1))
{
/* Try another I:line. */
continue;
Expand Down Expand Up @@ -661,7 +693,7 @@ int attach_Iline(aClient *cptr, struct hostent *hp, char *sockhost)

/* Various cases of +r. */
if (IsConfRestricted(aconf) ||
(!hp && IsConfRNoDNS(aconf)) ||
(!(*uhost) && IsConfRNoDNS(aconf)) ||
(!(cptr->flags & FLAGS_GOTID) && IsConfRNoIdent(aconf)))
{
SetRestricted(cptr);
Expand All @@ -678,7 +710,7 @@ int attach_Iline(aClient *cptr, struct hostent *hp, char *sockhost)
#endif

/* Copy uhost (hostname) over sockhost, if conf flag permits. */
if (hp && !IsConfNoResolve(aconf))
if (!IsCloaked(cptr) && *uhost && !IsConfNoResolve(aconf))
{
get_sockhost(cptr, uhost+ulen);
}
Expand All @@ -687,15 +719,6 @@ int attach_Iline(aClient *cptr, struct hostent *hp, char *sockhost)
{
find_bounce(cptr, ConfClass(aconf), -1);
}
/* Set cloaked hostname */
if(cptr->cloak_tmp && *cptr->cloak_tmp)
{
strncpyzt(cptr->sockhost, cptr->cloak_tmp, HOSTLEN + 1);
strncpyzt(cptr->user->host, cptr->cloak_tmp, HOSTLEN + 1);
MyFree(cptr->cloak_tmp);
cptr->cloak_tmp = NULL;
SetCloaked(cptr);
}
break;
}
if (retval == -2)
Expand Down Expand Up @@ -731,18 +754,19 @@ aConfItem *count_cnlines(Link *lp)
static int add_cidr_limit(aClient *cptr, aConfItem *aconf)
{
patricia_node_t *pnode;
struct IN_ADDR addr = get_client_addr(cptr);

if(aconf->class->cidr_amount == 0 || aconf->class->cidr_len == 0)
return -1;

pnode = patricia_match_ip(ConfCidrTree(aconf), &cptr->ip);
pnode = patricia_match_ip(ConfCidrTree(aconf), &addr);

/* doesnt exist, create and then allow */
/* doesn't exist, create and then allow */
if(pnode == NULL)
{
pnode = patricia_make_and_lookup_ip(ConfCidrTree(aconf),
&cptr->ip,
aconf->class->cidr_len);
&addr,
aconf->class->cidr_len);

if(pnode == NULL)
return -1;
Expand All @@ -761,11 +785,12 @@ static int add_cidr_limit(aClient *cptr, aConfItem *aconf)
static void remove_cidr_limit(aClient *cptr, aConfItem *aconf)
{
patricia_node_t *pnode;
struct IN_ADDR addr = get_client_addr(cptr);

if(ConfMaxCidrAmount(aconf) == 0 || ConfCidrLen(aconf) == 0)
return;

pnode = patricia_match_ip(ConfCidrTree(aconf), &cptr->ip);
pnode = patricia_match_ip(ConfCidrTree(aconf), &addr);

if(pnode == NULL)
return;
Expand Down Expand Up @@ -940,16 +965,12 @@ int attach_conf(aClient *cptr, aConfItem *aconf)
if (ConfMaxHLocal(aconf) > 0 || ConfMaxUHLocal(aconf) > 0 ||
ConfMaxHGlobal(aconf) > 0 || ConfMaxUHGlobal(aconf) > 0 )
{
if (IsSASLAuthed(cptr) && cptr->cloak_tmp != NULL)
if (IsCloaked(cptr))
{
/*
* Because all cloaked connections have the same IP address (CLOAK_IP),
* we use the cloaked hostname to check the Y-line limits (instead of IP or sockhost).
* (Originally from mh 2020-06-25)
*/
for ((user = hash_find_hostname(cptr->cloak_tmp, NULL)); user; user = user->hhnext)
// Check only by IP address because every SASL account has a unique IP address
for ((user = hash_find_ip(cptr->user->sip, NULL)); user; user = user->iphnext)
{
if (!mycmp(cptr->cloak_tmp, user->host))
if (!mycmp(cptr->user->sip, user->sip))
{
int ret = attach_conf_check_limits(cptr, aconf, user, &hcnt, &ucnt, &ghcnt, &gucnt);
if (ret != 0)
Expand Down Expand Up @@ -1136,8 +1157,7 @@ aConfItem *find_Oline(char *name, aClient *cptr)
** the ip does.
*/
if (match(tmp->host, userhost) && match(tmp->host, userip) &&
(!strchr(tmp->host, '/')
|| match_ipmask_client(tmp->host, cptr, 1)))
(!strchr(tmp->host, '/') || match_ipmask_client(tmp->host, cptr, 1, 1)))
continue;
if (tmp->clients < MaxLinks(Class(tmp)))
return tmp;
Expand Down Expand Up @@ -2229,6 +2249,7 @@ int find_kill(aClient *cptr, int timedklines, char **comment)
#endif
char *host, *ip, *name, *ident, *check;
aConfItem *tmp;
struct IN_ADDR addr;
#ifdef TKLINE
int tklines = 1;
#endif
Expand All @@ -2242,8 +2263,8 @@ int find_kill(aClient *cptr, int timedklines, char **comment)
}

host = cptr->sockhost;
ip = (char *) inetntop(AF_INET6, (char *)&cptr->ip, ipv6string,
sizeof(ipv6string));
addr = get_client_addr(cptr);
ip = (char *) inetntop(AF_INET6, &addr, ipv6string, sizeof(ipv6string));
if (!strcmp(host, ip))
ip = NULL; /* we don't have a name for the ip# */
name = cptr->user->username;
Expand Down Expand Up @@ -2315,26 +2336,23 @@ int find_kill(aClient *cptr, int timedklines, char **comment)
check = ident;
/* host & IP matching.. */
if (!ip) /* unresolved */
{
{
if (strchr(tmp->host, '/'))
{
if (match_ipmask_client((*tmp->host == '=') ?
tmp->host+1: tmp->host, cptr, 1))
continue;
}
else
if (match((*tmp->host == '=') ? tmp->host+1 :
tmp->host, host))
{
if (match_ipmask_client((*tmp->host == '=') ? tmp->host + 1 : tmp->host, cptr, 1, 1))
continue;
}
}
else if (match((*tmp->host == '=') ? tmp->host + 1 : tmp->host, host))
continue;
}
else if (*tmp->host == '=') /* numeric only */
continue;
else /* resolved */
if (strchr(tmp->host, '/'))
{
if (match_ipmask_client(tmp->host, cptr, 1))
{
if (match_ipmask_client(tmp->host, cptr, 1, 1))
continue;
}
}
else
if (match(tmp->host, ip) &&
match(tmp->host, host))
Expand Down Expand Up @@ -2555,7 +2573,7 @@ void find_bounce(aClient *cptr, int class, int fd)
{
if (strchr(aconf->host, '/'))
{
if (match_ipmask_client(aconf->host, cptr, 1))
if (match_ipmask_client(aconf->host, cptr, 1, 1))
continue;
}
else if (match(aconf->host, cptr->sockhost))
Expand Down Expand Up @@ -2771,9 +2789,8 @@ void do_kline(int tkline, char *who, time_t time, char *user, char *host, char *
/* unresolved */
if (strchr(aconf->host, '/'))
{
if (match_ipmask_client(*aconf->host == '=' ?
aconf->host + 1 : aconf->host,
acptr, 1))
if (match_ipmask_client(*aconf->host == '=' ? aconf->host + 1 : aconf->host,
acptr, 1, 1))
{
continue;
}
Expand All @@ -2798,7 +2815,7 @@ void do_kline(int tkline, char *who, time_t time, char *user, char *host, char *
}
if (strchr(aconf->host, '/'))
{
if (match_ipmask_client(aconf->host, acptr, 1))
if (match_ipmask_client(aconf->host, acptr, 1, 1))
{
continue;
}
Expand Down Expand Up @@ -2903,7 +2920,7 @@ int prep_kline(int tkline, aClient *cptr, aClient *sptr, int parc, char **parv)
/* disallow all forms of bad u@h format and block *@* without flags too */
err = 1;
}
if (!err && host && strchr(host, '/') && match_ipmask_client(host, sptr, 0) == -1)
if (!err && host && strchr(host, '/') && match_ipmask_client(host, sptr, 0, 1) == -1)
{
/* check validity of 1.2.3.0/24 or it will be spewing errors
** for every connecting client. */
Expand Down
2 changes: 1 addition & 1 deletion ircd/s_conf_ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ extern char *networkname;
#define EXTERN
#endif /* S_CONF_C */
EXTERN void det_confs_butmask (aClient *cptr, int mask);
EXTERN int match_ipmask_client (char *mask, aClient *cptr, int maskwithusername);
EXTERN int match_ipmask_client(char *mask, aClient *cptr, int maskwithusername, int prefer_cloak);
EXTERN int attach_Iline (aClient *cptr, Reg struct hostent *hp,
char *sockhost);
EXTERN aConfItem *count_cnlines (Reg Link *lp);
Expand Down
Loading