Merge pull request #313 from edk0/spoof-chban
Don't match iline-spoofed IPs for channel bans
This commit is contained in:
commit
2c11ccb99e
7 changed files with 121 additions and 133 deletions
|
@ -61,7 +61,7 @@ static int eb_canjoin(const char *data, struct Client *client_p,
|
|||
return EXTBAN_INVALID;
|
||||
#endif
|
||||
recurse = 1;
|
||||
ret = is_banned(chptr2, client_p, NULL, NULL, NULL, NULL) == CHFL_BAN ? EXTBAN_MATCH : EXTBAN_NOMATCH;
|
||||
ret = is_banned(chptr2, client_p, NULL, NULL, NULL) == CHFL_BAN ? EXTBAN_MATCH : EXTBAN_NOMATCH;
|
||||
recurse = 0;
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -32,36 +32,5 @@ _moddeinit(void)
|
|||
static int
|
||||
eb_hostmask(const char *banstr, struct Client *client_p, struct Channel *chptr, long mode_type)
|
||||
{
|
||||
char src_host[NAMELEN + USERLEN + HOSTLEN + 6];
|
||||
char src_iphost[NAMELEN + USERLEN + HOSTLEN + 6];
|
||||
char src_althost[NAMELEN + USERLEN + HOSTLEN + 6];
|
||||
char src_ip4host[NAMELEN + USERLEN + HOSTLEN + 6];
|
||||
struct sockaddr_in ip4;
|
||||
char *s = src_host, *s2 = src_iphost, *s3 = NULL, *s4 = NULL;
|
||||
|
||||
sprintf(src_host, "%s!%s@%s", client_p->name, client_p->username, client_p->host);
|
||||
sprintf(src_iphost, "%s!%s@%s", client_p->name, client_p->username, client_p->sockhost);
|
||||
|
||||
/* handle hostmangling if necessary */
|
||||
if (client_p->localClient->mangledhost != NULL)
|
||||
{
|
||||
if (!strcmp(client_p->host, client_p->localClient->mangledhost))
|
||||
sprintf(src_althost, "%s!%s@%s", client_p->name, client_p->username, client_p->orighost);
|
||||
else if (!IsDynSpoof(client_p))
|
||||
sprintf(src_althost, "%s!%s@%s", client_p->name, client_p->username, client_p->localClient->mangledhost);
|
||||
|
||||
s3 = src_althost;
|
||||
}
|
||||
|
||||
/* handle Teredo if necessary */
|
||||
if (GET_SS_FAMILY(&client_p->localClient->ip) == AF_INET6 && rb_ipv4_from_ipv6((const struct sockaddr_in6 *) &client_p->localClient->ip, &ip4))
|
||||
{
|
||||
sprintf(src_ip4host, "%s!%s@", client_p->name, client_p->username);
|
||||
s4 = src_ip4host + strlen(src_ip4host);
|
||||
rb_inet_ntop_sock((struct sockaddr *)&ip4,
|
||||
s4, src_ip4host + sizeof src_ip4host - s4);
|
||||
s4 = src_ip4host;
|
||||
}
|
||||
|
||||
return match(banstr, s) || match(banstr, s2) || (s3 != NULL && match(banstr, s3)) || (s4 != NULL && match(banstr, s4)) ? EXTBAN_MATCH : EXTBAN_NOMATCH;
|
||||
return client_matches_mask(client_p, banstr) ? EXTBAN_MATCH : EXTBAN_NOMATCH;
|
||||
}
|
||||
|
|
|
@ -215,10 +215,12 @@ extern int can_send(struct Channel *chptr, struct Client *who,
|
|||
struct membership *);
|
||||
extern bool flood_attack_channel(int p_or_n, struct Client *source_p,
|
||||
struct Channel *chptr, char *chname);
|
||||
struct matchset;
|
||||
extern int is_banned(struct Channel *chptr, struct Client *who,
|
||||
struct membership *msptr, const char *, const char *, const char **);
|
||||
struct membership *msptr, const struct matchset *ms,
|
||||
const char **);
|
||||
extern int is_quieted(struct Channel *chptr, struct Client *who,
|
||||
struct membership *msptr, const char *, const char *);
|
||||
struct membership *msptr, const struct matchset *ms);
|
||||
extern int can_join(struct Client *source_p, struct Channel *chptr,
|
||||
const char *key, const char **forward);
|
||||
|
||||
|
|
|
@ -59,6 +59,17 @@ int comp_with_mask_sock(struct sockaddr *addr, struct sockaddr *dest, unsigned i
|
|||
extern char *collapse(char *pattern);
|
||||
extern char *collapse_esc(char *pattern);
|
||||
|
||||
struct matchset {
|
||||
char host[2][NAMELEN + USERLEN + HOSTLEN + 6];
|
||||
char ip[2][NAMELEN + USERLEN + HOSTIPLEN + 6];
|
||||
};
|
||||
|
||||
struct Client;
|
||||
|
||||
void matchset_for_client(struct Client *who, struct matchset *m);
|
||||
bool client_matches_mask(struct Client *who, const char *mask);
|
||||
bool matches_mask(const struct matchset *m, const char *mask);
|
||||
|
||||
/*
|
||||
* irccmp - case insensitive comparison of s1 and s2
|
||||
*/
|
||||
|
|
124
ircd/channel.c
124
ircd/channel.c
|
@ -537,84 +537,41 @@ del_invite(struct Channel *chptr, struct Client *who)
|
|||
static int
|
||||
is_banned_list(struct Channel *chptr, rb_dlink_list *list,
|
||||
struct Client *who, struct membership *msptr,
|
||||
const char *s, const char *s2, const char **forward)
|
||||
const struct matchset *ms, const char **forward)
|
||||
{
|
||||
char src_host[NAMELEN + USERLEN + HOSTLEN + 6];
|
||||
char src_iphost[NAMELEN + USERLEN + HOSTLEN + 6];
|
||||
char src_althost[NAMELEN + USERLEN + HOSTLEN + 6];
|
||||
char src_ip4host[NAMELEN + USERLEN + HOSTLEN + 6];
|
||||
char *s3 = NULL;
|
||||
char *s4 = NULL;
|
||||
struct sockaddr_in ip4;
|
||||
struct matchset ms_;
|
||||
rb_dlink_node *ptr;
|
||||
struct Ban *actualBan = NULL;
|
||||
struct Ban *actualExcept = NULL;
|
||||
|
||||
if(!MyClient(who))
|
||||
if (!MyClient(who))
|
||||
return 0;
|
||||
|
||||
/* if the buffers havent been built, do it here */
|
||||
if(s == NULL)
|
||||
if (ms == NULL)
|
||||
{
|
||||
sprintf(src_host, "%s!%s@%s", who->name, who->username, who->host);
|
||||
sprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->sockhost);
|
||||
|
||||
s = src_host;
|
||||
s2 = src_iphost;
|
||||
}
|
||||
if(who->localClient->mangledhost != NULL)
|
||||
{
|
||||
/* if host mangling mode enabled, also check their real host */
|
||||
if(!strcmp(who->host, who->localClient->mangledhost))
|
||||
{
|
||||
sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->orighost);
|
||||
s3 = src_althost;
|
||||
}
|
||||
/* if host mangling mode not enabled and no other spoof,
|
||||
* also check the mangled form of their host */
|
||||
else if (!IsDynSpoof(who))
|
||||
{
|
||||
sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
|
||||
s3 = src_althost;
|
||||
}
|
||||
}
|
||||
if(GET_SS_FAMILY(&who->localClient->ip) == AF_INET6 &&
|
||||
rb_ipv4_from_ipv6((const struct sockaddr_in6 *)&who->localClient->ip, &ip4))
|
||||
{
|
||||
sprintf(src_ip4host, "%s!%s@", who->name, who->username);
|
||||
s4 = src_ip4host + strlen(src_ip4host);
|
||||
rb_inet_ntop_sock((struct sockaddr *)&ip4,
|
||||
s4, src_ip4host + sizeof src_ip4host - s4);
|
||||
s4 = src_ip4host;
|
||||
matchset_for_client(who, &ms_);
|
||||
ms = &ms_;
|
||||
}
|
||||
|
||||
RB_DLINK_FOREACH(ptr, list->head)
|
||||
{
|
||||
actualBan = ptr->data;
|
||||
if(match(actualBan->banstr, s) ||
|
||||
match(actualBan->banstr, s2) ||
|
||||
match_cidr(actualBan->banstr, s2) ||
|
||||
match_extban(actualBan->banstr, who, chptr, CHFL_BAN) ||
|
||||
(s3 != NULL && match(actualBan->banstr, s3)) ||
|
||||
(s4 != NULL && (match(actualBan->banstr, s4) || match_cidr(actualBan->banstr, s4)))
|
||||
)
|
||||
if (matches_mask(ms, actualBan->banstr))
|
||||
break;
|
||||
else
|
||||
actualBan = NULL;
|
||||
if (match_extban(actualBan->banstr, who, chptr, CHFL_BAN))
|
||||
break;
|
||||
actualBan = NULL;
|
||||
}
|
||||
|
||||
if((actualBan != NULL) && ConfigChannel.use_except)
|
||||
if ((actualBan != NULL) && ConfigChannel.use_except)
|
||||
{
|
||||
RB_DLINK_FOREACH(ptr, chptr->exceptlist.head)
|
||||
{
|
||||
actualExcept = ptr->data;
|
||||
|
||||
/* theyre exempted.. */
|
||||
if(match(actualExcept->banstr, s) ||
|
||||
match(actualExcept->banstr, s2) ||
|
||||
match_cidr(actualExcept->banstr, s2) ||
|
||||
match_extban(actualExcept->banstr, who, chptr, CHFL_EXCEPTION) ||
|
||||
(s3 != NULL && match(actualExcept->banstr, s3)))
|
||||
if (matches_mask(ms, actualExcept->banstr) ||
|
||||
match_extban(actualExcept->banstr, who, chptr, CHFL_BAN))
|
||||
{
|
||||
/* cache the fact theyre not banned */
|
||||
if(msptr != NULL)
|
||||
|
@ -660,7 +617,7 @@ is_banned_list(struct Channel *chptr, rb_dlink_list *list,
|
|||
*/
|
||||
int
|
||||
is_banned(struct Channel *chptr, struct Client *who, struct membership *msptr,
|
||||
const char *s, const char *s2, const char **forward)
|
||||
const struct matchset *ms, const char **forward)
|
||||
{
|
||||
#if 0
|
||||
if (chptr->last_checked_client != NULL &&
|
||||
|
@ -676,7 +633,7 @@ is_banned(struct Channel *chptr, struct Client *who, struct membership *msptr,
|
|||
|
||||
return chptr->last_checked_result;
|
||||
#else
|
||||
return is_banned_list(chptr, &chptr->banlist, who, msptr, s, s2, forward);
|
||||
return is_banned_list(chptr, &chptr->banlist, who, msptr, ms, forward);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -689,7 +646,7 @@ is_banned(struct Channel *chptr, struct Client *who, struct membership *msptr,
|
|||
*/
|
||||
int
|
||||
is_quieted(struct Channel *chptr, struct Client *who, struct membership *msptr,
|
||||
const char *s, const char *s2)
|
||||
const struct matchset *ms)
|
||||
{
|
||||
#if 0
|
||||
if (chptr->last_checked_client != NULL &&
|
||||
|
@ -705,7 +662,7 @@ is_quieted(struct Channel *chptr, struct Client *who, struct membership *msptr,
|
|||
|
||||
return chptr->last_checked_result;
|
||||
#else
|
||||
return is_banned_list(chptr, &chptr->quietlist, who, msptr, s, s2, NULL);
|
||||
return is_banned_list(chptr, &chptr->quietlist, who, msptr, ms, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -722,10 +679,7 @@ can_join(struct Client *source_p, struct Channel *chptr, const char *key, const
|
|||
rb_dlink_node *invite = NULL;
|
||||
rb_dlink_node *ptr;
|
||||
struct Ban *invex = NULL;
|
||||
char src_host[NAMELEN + USERLEN + HOSTLEN + 6];
|
||||
char src_iphost[NAMELEN + USERLEN + HOSTLEN + 6];
|
||||
char src_althost[NAMELEN + USERLEN + HOSTLEN + 6];
|
||||
int use_althost = 0;
|
||||
struct matchset ms;
|
||||
int i = 0;
|
||||
hook_data_channel moduledata;
|
||||
|
||||
|
@ -735,26 +689,9 @@ can_join(struct Client *source_p, struct Channel *chptr, const char *key, const
|
|||
moduledata.chptr = chptr;
|
||||
moduledata.approved = 0;
|
||||
|
||||
sprintf(src_host, "%s!%s@%s", source_p->name, source_p->username, source_p->host);
|
||||
sprintf(src_iphost, "%s!%s@%s", source_p->name, source_p->username, source_p->sockhost);
|
||||
if(source_p->localClient->mangledhost != NULL)
|
||||
{
|
||||
/* if host mangling mode enabled, also check their real host */
|
||||
if(!strcmp(source_p->host, source_p->localClient->mangledhost))
|
||||
{
|
||||
sprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->orighost);
|
||||
use_althost = 1;
|
||||
}
|
||||
/* if host mangling mode not enabled and no other spoof,
|
||||
* also check the mangled form of their host */
|
||||
else if (!IsDynSpoof(source_p))
|
||||
{
|
||||
sprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->localClient->mangledhost);
|
||||
use_althost = 1;
|
||||
}
|
||||
}
|
||||
matchset_for_client(source_p, &ms);
|
||||
|
||||
if((is_banned(chptr, source_p, NULL, src_host, src_iphost, forward)) == CHFL_BAN)
|
||||
if((is_banned(chptr, source_p, NULL, &ms, forward)) == CHFL_BAN)
|
||||
{
|
||||
moduledata.approved = ERR_BANNEDFROMCHAN;
|
||||
goto finish_join_check;
|
||||
|
@ -784,11 +721,8 @@ can_join(struct Client *source_p, struct Channel *chptr, const char *key, const
|
|||
RB_DLINK_FOREACH(ptr, chptr->invexlist.head)
|
||||
{
|
||||
invex = ptr->data;
|
||||
if(match(invex->banstr, src_host)
|
||||
|| match(invex->banstr, src_iphost)
|
||||
|| match_cidr(invex->banstr, src_iphost)
|
||||
|| match_extban(invex->banstr, source_p, chptr, CHFL_INVEX)
|
||||
|| (use_althost && match(invex->banstr, src_althost)))
|
||||
if (matches_mask(&ms, invex->banstr) ||
|
||||
match_extban(invex->banstr, source_p, chptr, CHFL_INVEX))
|
||||
break;
|
||||
}
|
||||
if(ptr == NULL)
|
||||
|
@ -879,8 +813,8 @@ can_send(struct Channel *chptr, struct Client *source_p, struct membership *mspt
|
|||
if(can_send_banned(msptr))
|
||||
moduledata.approved = CAN_SEND_NO;
|
||||
}
|
||||
else if(is_banned(chptr, source_p, msptr, NULL, NULL, NULL) == CHFL_BAN
|
||||
|| is_quieted(chptr, source_p, msptr, NULL, NULL) == CHFL_BAN)
|
||||
else if(is_banned(chptr, source_p, msptr, NULL, NULL) == CHFL_BAN
|
||||
|| is_quieted(chptr, source_p, msptr, NULL) == CHFL_BAN)
|
||||
moduledata.approved = CAN_SEND_NO;
|
||||
}
|
||||
|
||||
|
@ -964,14 +898,12 @@ find_bannickchange_channel(struct Client *client_p)
|
|||
struct Channel *chptr;
|
||||
struct membership *msptr;
|
||||
rb_dlink_node *ptr;
|
||||
char src_host[NAMELEN + USERLEN + HOSTLEN + 6];
|
||||
char src_iphost[NAMELEN + USERLEN + HOSTLEN + 6];
|
||||
struct matchset ms;
|
||||
|
||||
if (!MyClient(client_p))
|
||||
return NULL;
|
||||
|
||||
sprintf(src_host, "%s!%s@%s", client_p->name, client_p->username, client_p->host);
|
||||
sprintf(src_iphost, "%s!%s@%s", client_p->name, client_p->username, client_p->sockhost);
|
||||
matchset_for_client(client_p, &ms);
|
||||
|
||||
RB_DLINK_FOREACH(ptr, client_p->user->channel.head)
|
||||
{
|
||||
|
@ -985,8 +917,8 @@ find_bannickchange_channel(struct Client *client_p)
|
|||
if (can_send_banned(msptr))
|
||||
return chptr;
|
||||
}
|
||||
else if (is_banned(chptr, client_p, msptr, src_host, src_iphost, NULL) == CHFL_BAN
|
||||
|| is_quieted(chptr, client_p, msptr, src_host, src_iphost) == CHFL_BAN)
|
||||
else if (is_banned(chptr, client_p, msptr, &ms, NULL) == CHFL_BAN
|
||||
|| is_quieted(chptr, client_p, msptr, &ms) == CHFL_BAN)
|
||||
return chptr;
|
||||
}
|
||||
return NULL;
|
||||
|
|
74
ircd/match.c
74
ircd/match.c
|
@ -586,6 +586,80 @@ int ircncmp(const char *s1, const char *s2, int n)
|
|||
return (res);
|
||||
}
|
||||
|
||||
void matchset_for_client(struct Client *who, struct matchset *m)
|
||||
{
|
||||
unsigned hostn = 0;
|
||||
unsigned ipn = 0;
|
||||
|
||||
struct sockaddr_in ip4;
|
||||
|
||||
sprintf(m->host[hostn++], "%s!%s@%s", who->name, who->username, who->host);
|
||||
|
||||
if (!IsIPSpoof(who))
|
||||
{
|
||||
sprintf(m->ip[ipn++], "%s!%s@%s", who->name, who->username, who->sockhost);
|
||||
}
|
||||
|
||||
if (who->localClient->mangledhost != NULL)
|
||||
{
|
||||
/* if host mangling mode enabled, also check their real host */
|
||||
if (!strcmp(who->host, who->localClient->mangledhost))
|
||||
{
|
||||
sprintf(m->host[hostn++], "%s!%s@%s", who->name, who->username, who->orighost);
|
||||
}
|
||||
/* if host mangling mode not enabled and no other spoof,
|
||||
* also check the mangled form of their host */
|
||||
else if (!IsDynSpoof(who))
|
||||
{
|
||||
sprintf(m->host[hostn++], "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
|
||||
}
|
||||
}
|
||||
if (!IsIPSpoof(who) && GET_SS_FAMILY(&who->localClient->ip) == AF_INET6 &&
|
||||
rb_ipv4_from_ipv6((const struct sockaddr_in6 *)&who->localClient->ip, &ip4))
|
||||
{
|
||||
int n = sprintf(m->ip[ipn++], "%s!%s@", who->name, who->username);
|
||||
rb_inet_ntop_sock((struct sockaddr *)&ip4,
|
||||
m->ip[ipn] + n, sizeof m->ip[ipn] - n);
|
||||
}
|
||||
|
||||
for (int i = hostn; i < ARRAY_SIZE(m->host); i++)
|
||||
{
|
||||
m->host[i][0] = '\0';
|
||||
}
|
||||
for (int i = ipn; i < ARRAY_SIZE(m->ip); i++)
|
||||
{
|
||||
m->ip[i][0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
bool client_matches_mask(struct Client *who, const char *mask)
|
||||
{
|
||||
static struct matchset ms;
|
||||
matchset_for_client(who, &ms);
|
||||
return matches_mask(&ms, mask);
|
||||
}
|
||||
|
||||
bool matches_mask(const struct matchset *m, const char *mask)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(m->host); i++)
|
||||
{
|
||||
if (m->host[i][0] == '\0')
|
||||
break;
|
||||
if (match(mask, m->host[i]))
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < ARRAY_SIZE(m->ip); i++)
|
||||
{
|
||||
if (m->ip[i][0] == '\0')
|
||||
break;
|
||||
if (match(mask, m->ip[i]))
|
||||
return true;
|
||||
if (match_cidr(mask, m->ip[i]))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned char irctolower_tab[] = {
|
||||
0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
|
||||
0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
|
||||
|
|
|
@ -130,8 +130,8 @@ m_knock(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_
|
|||
if(MyClient(source_p))
|
||||
{
|
||||
/* don't allow a knock if the user is banned */
|
||||
if(is_banned(chptr, source_p, NULL, NULL, NULL, NULL) == CHFL_BAN ||
|
||||
is_quieted(chptr, source_p, NULL, NULL, NULL) == CHFL_BAN)
|
||||
if(is_banned(chptr, source_p, NULL, NULL, NULL) == CHFL_BAN ||
|
||||
is_quieted(chptr, source_p, NULL, NULL) == CHFL_BAN)
|
||||
{
|
||||
sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN,
|
||||
form_str(ERR_CANNOTSENDTOCHAN), name);
|
||||
|
|
Loading…
Reference in a new issue