- IPv6 clones detection support (). 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:
binki 2010-08-15 04:44:16 +00:00
parent fae4629c46
commit 2d10ab189d
7 changed files with 136 additions and 5 deletions

View file

@ -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.

View file

@ -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 &lt;server-name&gt;;</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 &lt;server-name&gt;;</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>

View file

@ -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

View file

@ -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 **);

View file

@ -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 {

View file

@ -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;
}

View file

@ -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
{