mirror of
https://github.com/pissnet/pissircd.git
synced 2025-08-06 10:15:24 +01:00
- IPv6 clones detection support (#2321). allow::ipv6-clone-mask determines the number of bits used when comparing two IPv6 addresses to determine if allow::maxperip is exceeded. This allows an admin to recognize that most IPv6 blocks are allocated to individuals, who might each get a /64 IPv6 block. set::default-ipv6-clone-mask defaults to 64 and provides default value for the allow blocks.
This commit is contained in:
parent
fae4629c46
commit
2d10ab189d
7 changed files with 136 additions and 5 deletions
6
Changes
6
Changes
|
@ -2099,3 +2099,9 @@
|
|||
it checks them also when the user is not currently cloaked (eg: did -x, or
|
||||
is currently using some VHOST).
|
||||
- Fixed client desynch caused by (un)banning, reported by Sephiroth (#2837).
|
||||
- IPv6 clones detection support (#2321). allow::ipv6-clone-mask determines
|
||||
the number of bits used when comparing two IPv6 addresses to determine if
|
||||
allow::maxperip is exceeded. This allows an admin to recognize that most
|
||||
IPv6 blocks are allocated to individuals, who might each get a /64 IPv6
|
||||
block. set::default-ipv6-clone-mask defaults to 64 and provides default
|
||||
value for the allow blocks.
|
||||
|
|
|
@ -849,6 +849,7 @@ allow {
|
|||
class <connection-class>;
|
||||
password <connection-password> { <auth-type>; };
|
||||
maxperip <max-connections-per-ip>;
|
||||
ipv6-clone-mask <number-of-bits>;
|
||||
redirect-server <server-to-forward-to>;
|
||||
redirect-port <port-to-forward-to>;
|
||||
options {
|
||||
|
@ -879,6 +880,16 @@ allow {
|
|||
<p><b>maxperip</b> (optional, but recommended)<br>
|
||||
Allows you to specify how many connections per IP are allowed to this server (ex: maxperip 4;).
|
||||
</p>
|
||||
<p id="allowblock_ipv6clonemask"><b>ipv6-clone-mask</b>
|
||||
(optional, defaults to <a href="#set_defaultipv6clonemask">set::default-ipv6-clone-mask</a>)<br />
|
||||
This option controls clone detection. If two clients connect from different IPv6 addresses
|
||||
but only the last few bits are different, there is almost a guarantee that both clients
|
||||
are really one person. This option only affects the enforcement of
|
||||
<a href="#allowblock_maxperip">allow::maxperip</a>. For example, if you set this option to
|
||||
128, then each IPv6 address will be considered unique. Because of current IP allocation
|
||||
policies, it is recommended that your most general <a href="#allowblock">allow block</a>
|
||||
use a value of 64.
|
||||
</p>
|
||||
<p><b>redirect-server</b> (optional)<br>
|
||||
If the class is full, redirect users to this server (if clients supports it [mIRC 6 does]).</p>
|
||||
<p><b>redirect-port</b> (optional)<br>
|
||||
|
@ -2492,6 +2503,12 @@ set {
|
|||
<p><font class="set">set::default-server <server-name>;</font><br>
|
||||
Defines the name of the default server to tell users to connect to if this server
|
||||
is full.</p>
|
||||
<p id="set_defaultipv6clonemask">
|
||||
<font class="set">set::default-ipv6-clone-mask</font><br />
|
||||
The default IPv6 clone detection mask. See
|
||||
<a href="#allowblock_ipv6clonemask">allow::ipv6-clone-mask</a>. The default value for this
|
||||
setting is 64.
|
||||
</p>
|
||||
<p id="set-services-server"><font class="set">set::services-server <server-name>;</font><br>
|
||||
Specifies the name of the server that the services bots are connected to. Required,
|
||||
set it to something like services.yournet.com if you don't have services.</p>
|
||||
|
|
|
@ -164,6 +164,9 @@ struct zConfiguration {
|
|||
int watch_away_notification;
|
||||
int uhnames;
|
||||
aNetwork network;
|
||||
#ifdef INET6
|
||||
unsigned short default_ipv6_clone_mask;
|
||||
#endif /* INET6 */
|
||||
};
|
||||
|
||||
#ifndef DYNCONF_C
|
||||
|
|
|
@ -136,6 +136,9 @@ ConfigItem_help *Find_Help(char *command);
|
|||
int AllowClient(aClient *cptr, struct hostent *hp, char *sockhost, char *username);
|
||||
int parse_netmask(const char *text, struct irc_netmask *netmask);
|
||||
int match_ip(struct IN_ADDR addr, char *uhost, char *mask, struct irc_netmask *netmask);
|
||||
#ifdef INET6
|
||||
int match_ipv6(struct IN_ADDR *addr, struct IN_ADDR *mask, int bits);
|
||||
#endif
|
||||
ConfigItem_ban *Find_ban_ip(aClient *sptr);
|
||||
extern MODVAR Link *Servers;
|
||||
void add_ListItem(ListStruct *, ListStruct **);
|
||||
|
|
|
@ -1210,6 +1210,9 @@ struct _configitem_allow {
|
|||
ConfigItem_class *class;
|
||||
struct irc_netmask *netmask;
|
||||
ConfigFlag_allow flags;
|
||||
#ifdef INET6
|
||||
unsigned short ipv6_clone_mask;
|
||||
#endif /* INET6 */
|
||||
};
|
||||
|
||||
struct _configitem_oper {
|
||||
|
|
|
@ -295,6 +295,8 @@ int parse_netmask(const char *text, struct irc_netmask *netmask)
|
|||
/* The address matching stuff... */
|
||||
/* int match_ipv6(struct IN_ADDR *, struct IN_ADDR *, int)
|
||||
* Input: An IP address, an IP mask, the number of bits in the mask.
|
||||
* Only the first bits of the IP mask will be compared, so
|
||||
* it doesn't need to be zeroed out after bits bits.
|
||||
* Output: if match, 1 else 0
|
||||
* Side effects: None
|
||||
*/
|
||||
|
@ -308,7 +310,8 @@ int match_ipv6(struct IN_ADDR *addr, struct IN_ADDR *mask, int bits)
|
|||
return 0;
|
||||
if ((m = bits % 8) == 0)
|
||||
return 1;
|
||||
if ((addr->s6_addr[n] & ~((1 << (8 - m)) - 1)) == mask->s6_addr[n])
|
||||
if ((addr->s6_addr[n] & ~((1 << (8 - m)) - 1))
|
||||
== (mask->s6_addr[n] & ~((1 << (8 - m)) - 1)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
104
src/s_conf.c
104
src/s_conf.c
|
@ -1725,6 +1725,9 @@ void config_setdefaultsettings(aConfiguration *i)
|
|||
i->watch_away_notification = 1;
|
||||
i->new_linking_protocol = 1;
|
||||
i->uhnames = 1;
|
||||
#ifdef INET6
|
||||
i->default_ipv6_clone_mask = 64;
|
||||
#endif /* INET6 */
|
||||
}
|
||||
|
||||
/* 1: needed for set::options::allow-part-if-shunned,
|
||||
|
@ -2469,6 +2472,9 @@ int config_run()
|
|||
ConfigCommand *cc;
|
||||
int errors = 0;
|
||||
Hook *h;
|
||||
#ifdef INET6
|
||||
ConfigItem_allow *allow;
|
||||
#endif /* INET6 */
|
||||
for (cfptr = conf; cfptr; cfptr = cfptr->cf_next)
|
||||
{
|
||||
if (config_verbose > 1)
|
||||
|
@ -2491,6 +2497,17 @@ int config_run()
|
|||
}
|
||||
}
|
||||
}
|
||||
#ifdef INET6
|
||||
/*
|
||||
* transfer default values from set::ipv6_clones_mask into
|
||||
* each individual allow block. If other similar things like
|
||||
* this stack up here, perhaps this shoul be moved to another
|
||||
* function.
|
||||
*/
|
||||
for(allow = conf_allow; allow; allow = (ConfigItem_allow *)allow->next)
|
||||
if(!allow->ipv6_clone_mask)
|
||||
allow->ipv6_clone_mask = tempiConf.default_ipv6_clone_mask;
|
||||
#endif /* INET6 */
|
||||
|
||||
close_listeners();
|
||||
listen_cleanup();
|
||||
|
@ -2884,6 +2901,9 @@ int AllowClient(aClient *cptr, struct hostent *hp, char *sockhost, char *usernam
|
|||
int i, ii = 0;
|
||||
static char uhost[HOSTLEN + USERLEN + 3];
|
||||
static char fullname[HOSTLEN + 1];
|
||||
#ifdef INET6
|
||||
short is_ipv4;
|
||||
#endif /* INET6 */
|
||||
|
||||
for (aconf = conf_allow; aconf; aconf = (ConfigItem_allow *) aconf->next)
|
||||
{
|
||||
|
@ -2958,16 +2978,27 @@ int AllowClient(aClient *cptr, struct hostent *hp, char *sockhost, char *usernam
|
|||
else
|
||||
strncpyzt(uhost, sockhost, sizeof(uhost));
|
||||
get_sockhost(cptr, uhost);
|
||||
#ifdef INET6
|
||||
is_ipv4 = IN6_IS_ADDR_V4MAPPED(&cptr->ip);
|
||||
#endif /* INET6 */
|
||||
|
||||
/* FIXME */
|
||||
if (aconf->maxperip)
|
||||
{
|
||||
ii = 1;
|
||||
for (i = LastSlot; i >= 0; i--)
|
||||
if (local[i] && MyClient(local[i]) &&
|
||||
if (local[i] && MyClient(local[i])
|
||||
#ifndef INET6
|
||||
local[i]->ip.S_ADDR == cptr->ip.S_ADDR)
|
||||
&& local[i]->ip.S_ADDR == cptr->ip.S_ADDR)
|
||||
#else
|
||||
!bcmp(local[i]->ip.S_ADDR, cptr->ip.S_ADDR, sizeof(cptr->ip.S_ADDR)))
|
||||
/*
|
||||
* match IPv4 exactly and the ipv6
|
||||
* based on ipv6_clone_mask.
|
||||
*/
|
||||
&& (is_ipv4
|
||||
? !bcmp(local[i]->ip.S_ADDR, cptr->ip.S_ADDR, sizeof(cptr->ip.S_ADDR))
|
||||
: match_ipv6(&local[i]->ip, &cptr->ip, aconf->ipv6_clone_mask)))
|
||||
|
||||
#endif
|
||||
{
|
||||
ii++;
|
||||
|
@ -4780,6 +4811,17 @@ int _conf_allow(ConfigFile *conf, ConfigEntry *ce)
|
|||
allow->server = strdup(cep->ce_vardata);
|
||||
else if (!strcmp(cep->ce_varname, "redirect-port"))
|
||||
allow->port = atoi(cep->ce_vardata);
|
||||
else if (!strcmp(cep->ce_varname, "ipv6-clone-mask"))
|
||||
{
|
||||
#ifdef INET6
|
||||
/*
|
||||
* If this item isn't set explicitly by the
|
||||
* user, the value will temporarily be
|
||||
* zero. Defaults are applied in config_run().
|
||||
*/
|
||||
allow->ipv6_clone_mask = atoi(cep->ce_vardata);
|
||||
#endif /* INET6 */
|
||||
}
|
||||
else if (!strcmp(cep->ce_varname, "options"))
|
||||
{
|
||||
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
||||
|
@ -4885,6 +4927,30 @@ int _test_allow(ConfigFile *conf, ConfigEntry *ce)
|
|||
errors++;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(cep->ce_varname, "ipv6-clone-mask"))
|
||||
{
|
||||
/* keep this in sync with _test_set() */
|
||||
int ipv6mask;
|
||||
ipv6mask = atoi(cep->ce_vardata);
|
||||
if (ipv6mask == 0)
|
||||
{
|
||||
config_error("%s:%d: allow::ipv6-clone-mask given a value of zero. This cannnot be correct, as it would treat all IPv6 hosts as one host.",
|
||||
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
||||
errors++;
|
||||
}
|
||||
if (ipv6mask > 128)
|
||||
{
|
||||
config_error("%s:%d: set::default-ipv6-clone-mask was set to %d. The maximum value is 128.",
|
||||
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
||||
ipv6mask);
|
||||
errors++;
|
||||
}
|
||||
if (ipv6mask <= 32)
|
||||
{
|
||||
config_warn("%s:%d: allow::ipv6-clone-mask was given a very small value.",
|
||||
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(cep->ce_varname, "hostname"))
|
||||
{
|
||||
if (has_hostname)
|
||||
|
@ -7539,6 +7605,12 @@ int _conf_set(ConfigFile *conf, ConfigEntry *ce)
|
|||
|
||||
}
|
||||
#endif /* USE_SSL */
|
||||
}
|
||||
else if (!strcmp(cep->ce_varname, "default-ipv6-clone-mask"))
|
||||
{
|
||||
#ifdef INET6
|
||||
tempiConf.default_ipv6_clone_mask = atoi(cep->ce_vardata);
|
||||
#endif /* INET6 */
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -8472,7 +8544,31 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce)
|
|||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
#endif /* USE_SSL */
|
||||
}
|
||||
else if (!strcmp(cep->ce_varname, "default-ipv6-clone-mask"))
|
||||
{
|
||||
/* keep this in sync with _test_allow() */
|
||||
int ipv6mask;
|
||||
ipv6mask = atoi(cep->ce_vardata);
|
||||
if (ipv6mask == 0)
|
||||
{
|
||||
config_error("%s:%d: set::default-ipv6-clone-mask given a value of zero. This cannnot be correct, as it would treat all IPv6 hosts as one host.",
|
||||
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
||||
errors++;
|
||||
}
|
||||
if (ipv6mask > 128)
|
||||
{
|
||||
config_error("%s:%d: set::default-ipv6-clone-mask was set to %d. The maximum value is 128.",
|
||||
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
||||
ipv6mask);
|
||||
errors++;
|
||||
}
|
||||
if (ipv6mask <= 32)
|
||||
{
|
||||
config_warn("%s:%d: set::default-ipv6-clone-mask was given a very small value.",
|
||||
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue