mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-06 20:55:13 +02:00
xt_geoip: IPv6 support
This commit is contained in:
@@ -4,6 +4,8 @@ HEAD
|
|||||||
Fixes:
|
Fixes:
|
||||||
- Update to ipset 4.5
|
- Update to ipset 4.5
|
||||||
* the iptreemap type used wrong gfp flags when deleting entries
|
* the iptreemap type used wrong gfp flags when deleting entries
|
||||||
|
Enhancements:
|
||||||
|
- IPv6 support for xt_geoip
|
||||||
|
|
||||||
|
|
||||||
v1.31 (2010-11-05)
|
v1.31 (2010-11-05)
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
* "geoip" match extension for iptables
|
* "geoip" match extension for iptables
|
||||||
* Copyright © Samuel Jean <peejix [at] people netfilter org>, 2004 - 2008
|
* Copyright © Samuel Jean <peejix [at] people netfilter org>, 2004 - 2008
|
||||||
* Copyright © Nicolas Bouliane <acidfu [at] people netfilter org>, 2004 - 2008
|
* Copyright © Nicolas Bouliane <acidfu [at] people netfilter org>, 2004 - 2008
|
||||||
* Jan Engelhardt <jengelh [at] medozas de>, 2008
|
* Jan Engelhardt <jengelh [at] medozas de>, 2008-2011
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License; either
|
* modify it under the terms of the GNU General Public License; either
|
||||||
@@ -49,20 +49,28 @@ static struct option geoip_opts[] = {
|
|||||||
{NULL},
|
{NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct geoip_subnet4 *
|
static void *
|
||||||
geoip_get_subnets(const char *code, uint32_t *count)
|
geoip_get_subnets(const char *code, uint32_t *count, uint8_t nfproto)
|
||||||
{
|
{
|
||||||
struct geoip_subnet4 *subnets;
|
void *subnets;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
/* Use simple integer vector files */
|
/* Use simple integer vector files */
|
||||||
|
if (nfproto == NFPROTO_IPV6) {
|
||||||
#if __BYTE_ORDER == _BIG_ENDIAN
|
#if __BYTE_ORDER == _BIG_ENDIAN
|
||||||
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/BE/%s.iv4", code);
|
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/BE/%s.iv6", code);
|
||||||
#else
|
#else
|
||||||
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/LE/%s.iv4", code);
|
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/LE/%s.iv6", code);
|
||||||
#endif
|
#endif
|
||||||
|
} else {
|
||||||
|
#if __BYTE_ORDER == _BIG_ENDIAN
|
||||||
|
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/BE/%s.iv4", code);
|
||||||
|
#else
|
||||||
|
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/LE/%s.iv4", code);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if ((fd = open(buf, O_RDONLY)) < 0) {
|
if ((fd = open(buf, O_RDONLY)) < 0) {
|
||||||
fprintf(stderr, "Could not open %s: %s\n", buf, strerror(errno));
|
fprintf(stderr, "Could not open %s: %s\n", buf, strerror(errno));
|
||||||
@@ -70,20 +78,31 @@ geoip_get_subnets(const char *code, uint32_t *count)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fstat(fd, &sb);
|
fstat(fd, &sb);
|
||||||
if (sb.st_size % sizeof(struct geoip_subnet4) != 0)
|
*count = sb.st_size;
|
||||||
xtables_error(OTHER_PROBLEM, "Database file %s seems to be "
|
switch (nfproto) {
|
||||||
"corrupted", buf);
|
case NFPROTO_IPV6:
|
||||||
|
if (sb.st_size % sizeof(struct geoip_subnet6) != 0)
|
||||||
|
xtables_error(OTHER_PROBLEM,
|
||||||
|
"Database file %s seems to be corrupted", buf);
|
||||||
|
*count /= sizeof(struct geoip_subnet6);
|
||||||
|
break;
|
||||||
|
case NFPROTO_IPV4:
|
||||||
|
if (sb.st_size % sizeof(struct geoip_subnet4) != 0)
|
||||||
|
xtables_error(OTHER_PROBLEM,
|
||||||
|
"Database file %s seems to be corrupted", buf);
|
||||||
|
*count /= sizeof(struct geoip_subnet4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
subnets = malloc(sb.st_size);
|
subnets = malloc(sb.st_size);
|
||||||
if (subnets == NULL)
|
if (subnets == NULL)
|
||||||
xtables_error(OTHER_PROBLEM, "geoip: insufficient memory");
|
xtables_error(OTHER_PROBLEM, "geoip: insufficient memory");
|
||||||
read(fd, subnets, sb.st_size);
|
read(fd, subnets, sb.st_size);
|
||||||
close(fd);
|
close(fd);
|
||||||
*count = sb.st_size / sizeof(struct geoip_subnet4);
|
|
||||||
return subnets;
|
return subnets;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct geoip_country_user *geoip_load_cc(const char *code,
|
static struct geoip_country_user *geoip_load_cc(const char *code,
|
||||||
unsigned short cc)
|
unsigned short cc, uint8_t nfproto)
|
||||||
{
|
{
|
||||||
struct geoip_country_user *ginfo;
|
struct geoip_country_user *ginfo;
|
||||||
ginfo = malloc(sizeof(struct geoip_country_user));
|
ginfo = malloc(sizeof(struct geoip_country_user));
|
||||||
@@ -91,7 +110,8 @@ static struct geoip_country_user *geoip_load_cc(const char *code,
|
|||||||
if (!ginfo)
|
if (!ginfo)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
ginfo->subnets = (unsigned long)geoip_get_subnets(code, &ginfo->count);
|
ginfo->subnets = (unsigned long)geoip_get_subnets(code,
|
||||||
|
&ginfo->count, nfproto);
|
||||||
ginfo->cc = cc;
|
ginfo->cc = cc;
|
||||||
|
|
||||||
return ginfo;
|
return ginfo;
|
||||||
@@ -134,7 +154,7 @@ check_geoip_cc(char *cc, u_int16_t cc_used[], u_int8_t count)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int parse_geoip_cc(const char *ccstr, uint16_t *cc,
|
static unsigned int parse_geoip_cc(const char *ccstr, uint16_t *cc,
|
||||||
union geoip_country_group *mem)
|
union geoip_country_group *mem, uint8_t nfproto)
|
||||||
{
|
{
|
||||||
char *buffer, *cp, *next;
|
char *buffer, *cp, *next;
|
||||||
u_int8_t i, count = 0;
|
u_int8_t i, count = 0;
|
||||||
@@ -151,7 +171,8 @@ static unsigned int parse_geoip_cc(const char *ccstr, uint16_t *cc,
|
|||||||
if (next) *next++ = '\0';
|
if (next) *next++ = '\0';
|
||||||
|
|
||||||
if ((cctmp = check_geoip_cc(cp, cc, count)) != 0) {
|
if ((cctmp = check_geoip_cc(cp, cc, count)) != 0) {
|
||||||
if ((mem[count++].user = (unsigned long)geoip_load_cc(cp, cctmp)) == 0)
|
if ((mem[count++].user =
|
||||||
|
(unsigned long)geoip_load_cc(cp, cctmp, nfproto)) == 0)
|
||||||
xtables_error(OTHER_PROBLEM,
|
xtables_error(OTHER_PROBLEM,
|
||||||
"geoip: insufficient memory available");
|
"geoip: insufficient memory available");
|
||||||
cc[count-1] = cctmp;
|
cc[count-1] = cctmp;
|
||||||
@@ -170,11 +191,9 @@ static unsigned int parse_geoip_cc(const char *ccstr, uint16_t *cc,
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int geoip_parse(int c, char **argv, int invert, unsigned int *flags,
|
static int geoip_parse(int c, bool invert, unsigned int *flags,
|
||||||
const void *entry, struct xt_entry_match **match)
|
const char *arg, struct xt_geoip_match_info *info, uint8_t nfproto)
|
||||||
{
|
{
|
||||||
struct xt_geoip_match_info *info = (void *)(*match)->data;
|
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '1':
|
case '1':
|
||||||
if (*flags & (XT_GEOIP_SRC | XT_GEOIP_DST))
|
if (*flags & (XT_GEOIP_SRC | XT_GEOIP_DST))
|
||||||
@@ -186,7 +205,8 @@ static int geoip_parse(int c, char **argv, int invert, unsigned int *flags,
|
|||||||
if (invert)
|
if (invert)
|
||||||
*flags |= XT_GEOIP_INV;
|
*flags |= XT_GEOIP_INV;
|
||||||
|
|
||||||
info->count = parse_geoip_cc(argv[optind-1], info->cc, info->mem);
|
info->count = parse_geoip_cc(arg, info->cc, info->mem,
|
||||||
|
nfproto);
|
||||||
info->flags = *flags;
|
info->flags = *flags;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -200,7 +220,8 @@ static int geoip_parse(int c, char **argv, int invert, unsigned int *flags,
|
|||||||
if (invert)
|
if (invert)
|
||||||
*flags |= XT_GEOIP_INV;
|
*flags |= XT_GEOIP_INV;
|
||||||
|
|
||||||
info->count = parse_geoip_cc(argv[optind-1], info->cc, info->mem);
|
info->count = parse_geoip_cc(arg, info->cc, info->mem,
|
||||||
|
nfproto);
|
||||||
info->flags = *flags;
|
info->flags = *flags;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -208,6 +229,20 @@ static int geoip_parse(int c, char **argv, int invert, unsigned int *flags,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int geoip_parse6(int c, char **argv, int invert, unsigned int *flags,
|
||||||
|
const void *entry, struct xt_entry_match **match)
|
||||||
|
{
|
||||||
|
return geoip_parse(c, invert, flags, optarg,
|
||||||
|
(void *)(*match)->data, NFPROTO_IPV6);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int geoip_parse4(int c, char **argv, int invert, unsigned int *flags,
|
||||||
|
const void *entry, struct xt_entry_match **match)
|
||||||
|
{
|
||||||
|
return geoip_parse(c, invert, flags, optarg,
|
||||||
|
(void *)(*match)->data, NFPROTO_IPV4);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
geoip_final_check(unsigned int flags)
|
geoip_final_check(unsigned int flags)
|
||||||
{
|
{
|
||||||
@@ -260,22 +295,39 @@ geoip_save(const void *ip, const struct xt_entry_match *match)
|
|||||||
printf(" ");
|
printf(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct xtables_match geoip_match = {
|
static struct xtables_match geoip_match[] = {
|
||||||
.family = NFPROTO_IPV4,
|
{
|
||||||
.name = "geoip",
|
.family = NFPROTO_IPV6,
|
||||||
.revision = 1,
|
.name = "geoip",
|
||||||
.version = XTABLES_VERSION,
|
.revision = 1,
|
||||||
.size = XT_ALIGN(sizeof(struct xt_geoip_match_info)),
|
.version = XTABLES_VERSION,
|
||||||
.userspacesize = offsetof(struct xt_geoip_match_info, mem),
|
.size = XT_ALIGN(sizeof(struct xt_geoip_match_info)),
|
||||||
.help = geoip_help,
|
.userspacesize = offsetof(struct xt_geoip_match_info, mem),
|
||||||
.parse = geoip_parse,
|
.help = geoip_help,
|
||||||
.final_check = geoip_final_check,
|
.parse = geoip_parse6,
|
||||||
.print = geoip_print,
|
.final_check = geoip_final_check,
|
||||||
.save = geoip_save,
|
.print = geoip_print,
|
||||||
.extra_opts = geoip_opts,
|
.save = geoip_save,
|
||||||
|
.extra_opts = geoip_opts,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.family = NFPROTO_IPV4,
|
||||||
|
.name = "geoip",
|
||||||
|
.revision = 1,
|
||||||
|
.version = XTABLES_VERSION,
|
||||||
|
.size = XT_ALIGN(sizeof(struct xt_geoip_match_info)),
|
||||||
|
.userspacesize = offsetof(struct xt_geoip_match_info, mem),
|
||||||
|
.help = geoip_help,
|
||||||
|
.parse = geoip_parse4,
|
||||||
|
.final_check = geoip_final_check,
|
||||||
|
.print = geoip_print,
|
||||||
|
.save = geoip_save,
|
||||||
|
.extra_opts = geoip_opts,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static __attribute__((constructor)) void geoip_mt_ldr(void)
|
static __attribute__((constructor)) void geoip_mt_ldr(void)
|
||||||
{
|
{
|
||||||
xtables_register_match(&geoip_match);
|
xtables_register_matches(geoip_match,
|
||||||
|
sizeof(geoip_match) / sizeof(*geoip_match));
|
||||||
}
|
}
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
* Samuel Jean & Nicolas Bouliane
|
* Samuel Jean & Nicolas Bouliane
|
||||||
*/
|
*/
|
||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
|
#include <linux/ipv6.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
@@ -27,31 +28,49 @@ MODULE_LICENSE("GPL");
|
|||||||
MODULE_AUTHOR("Nicolas Bouliane");
|
MODULE_AUTHOR("Nicolas Bouliane");
|
||||||
MODULE_AUTHOR("Samuel Jean");
|
MODULE_AUTHOR("Samuel Jean");
|
||||||
MODULE_DESCRIPTION("xtables module for geoip match");
|
MODULE_DESCRIPTION("xtables module for geoip match");
|
||||||
|
MODULE_ALIAS("ip6t_geoip");
|
||||||
MODULE_ALIAS("ipt_geoip");
|
MODULE_ALIAS("ipt_geoip");
|
||||||
|
|
||||||
|
enum geoip_proto {
|
||||||
|
GEOIPROTO_IPV6,
|
||||||
|
GEOIPROTO_IPV4,
|
||||||
|
__GEOIPROTO_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @list: anchor point for geoip_head
|
* @list: anchor point for geoip_head
|
||||||
* @subnets: packed ordered list of ranges
|
* @subnets: packed ordered list of ranges (either v6 or v4)
|
||||||
* @count: number of ranges
|
* @count: number of ranges
|
||||||
* @cc: country code
|
* @cc: country code
|
||||||
*/
|
*/
|
||||||
struct geoip_country_kernel {
|
struct geoip_country_kernel {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct geoip_subnet4 *subnets;
|
void *subnets;
|
||||||
atomic_t ref;
|
atomic_t ref;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
unsigned short cc;
|
unsigned short cc;
|
||||||
};
|
};
|
||||||
|
|
||||||
static LIST_HEAD(geoip_head);
|
static struct list_head geoip_head[__GEOIPROTO_MAX];
|
||||||
static DEFINE_SPINLOCK(geoip_lock);
|
static DEFINE_SPINLOCK(geoip_lock);
|
||||||
|
|
||||||
|
static const enum geoip_proto nfp2geo[] = {
|
||||||
|
[NFPROTO_IPV6] = GEOIPROTO_IPV6,
|
||||||
|
[NFPROTO_IPV4] = GEOIPROTO_IPV4,
|
||||||
|
};
|
||||||
|
static const size_t geoproto_size[] = {
|
||||||
|
[GEOIPROTO_IPV6] = sizeof(struct geoip_subnet6),
|
||||||
|
[GEOIPROTO_IPV4] = sizeof(struct geoip_subnet4),
|
||||||
|
};
|
||||||
|
|
||||||
static struct geoip_country_kernel *
|
static struct geoip_country_kernel *
|
||||||
geoip_add_node(const struct geoip_country_user __user *umem_ptr)
|
geoip_add_node(const struct geoip_country_user __user *umem_ptr,
|
||||||
|
enum geoip_proto proto)
|
||||||
{
|
{
|
||||||
struct geoip_country_user umem;
|
struct geoip_country_user umem;
|
||||||
struct geoip_country_kernel *p;
|
struct geoip_country_kernel *p;
|
||||||
struct geoip_subnet4 *subnet;
|
size_t size;
|
||||||
|
void *subnet;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (copy_from_user(&umem, umem_ptr, sizeof(umem)) != 0)
|
if (copy_from_user(&umem, umem_ptr, sizeof(umem)) != 0)
|
||||||
@@ -63,15 +82,14 @@ geoip_add_node(const struct geoip_country_user __user *umem_ptr)
|
|||||||
|
|
||||||
p->count = umem.count;
|
p->count = umem.count;
|
||||||
p->cc = umem.cc;
|
p->cc = umem.cc;
|
||||||
|
size = p->count * geoproto_size[proto];
|
||||||
subnet = vmalloc(p->count * sizeof(struct geoip_subnet4));
|
subnet = vmalloc(size);
|
||||||
if (subnet == NULL) {
|
if (subnet == NULL) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto free_p;
|
goto free_p;
|
||||||
}
|
}
|
||||||
if (copy_from_user(subnet,
|
if (copy_from_user(subnet,
|
||||||
(const void __user *)(unsigned long)umem.subnets,
|
(const void __user *)(unsigned long)umem.subnets, size) != 0) {
|
||||||
p->count * sizeof(struct geoip_subnet4)) != 0) {
|
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
goto free_s;
|
goto free_s;
|
||||||
}
|
}
|
||||||
@@ -81,7 +99,7 @@ geoip_add_node(const struct geoip_country_user __user *umem_ptr)
|
|||||||
INIT_LIST_HEAD(&p->list);
|
INIT_LIST_HEAD(&p->list);
|
||||||
|
|
||||||
spin_lock(&geoip_lock);
|
spin_lock(&geoip_lock);
|
||||||
list_add_tail_rcu(&p->list, &geoip_head);
|
list_add_tail_rcu(&p->list, &geoip_head[proto]);
|
||||||
spin_unlock(&geoip_lock);
|
spin_unlock(&geoip_lock);
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
@@ -112,12 +130,13 @@ static void geoip_try_remove_node(struct geoip_country_kernel *p)
|
|||||||
kfree(p);
|
kfree(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct geoip_country_kernel *find_node(unsigned short cc)
|
static struct geoip_country_kernel *find_node(unsigned short cc,
|
||||||
|
enum geoip_proto proto)
|
||||||
{
|
{
|
||||||
struct geoip_country_kernel *p;
|
struct geoip_country_kernel *p;
|
||||||
spin_lock(&geoip_lock);
|
spin_lock(&geoip_lock);
|
||||||
|
|
||||||
list_for_each_entry_rcu(p, &geoip_head, list)
|
list_for_each_entry_rcu(p, &geoip_head[proto], list)
|
||||||
if (p->cc == cc) {
|
if (p->cc == cc) {
|
||||||
atomic_inc(&p->ref);
|
atomic_inc(&p->ref);
|
||||||
spin_unlock(&geoip_lock);
|
spin_unlock(&geoip_lock);
|
||||||
@@ -128,6 +147,72 @@ static struct geoip_country_kernel *find_node(unsigned short cc)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
ipv6_cmp(const struct in6_addr *p, const struct in6_addr *q)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
if (p->s6_addr32[i] < q->s6_addr32[i])
|
||||||
|
return -1;
|
||||||
|
else if (p->s6_addr32[i] > q->s6_addr32[i])
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool geoip_bsearch6(const struct geoip_subnet6 *range,
|
||||||
|
const struct in6_addr *addr, int lo, int hi)
|
||||||
|
{
|
||||||
|
int mid;
|
||||||
|
|
||||||
|
if (hi <= lo)
|
||||||
|
return false;
|
||||||
|
mid = (lo + hi) / 2;
|
||||||
|
if (ipv6_cmp(&range[mid].begin, addr) <= 0 &&
|
||||||
|
ipv6_cmp(addr, &range[mid].end) <= 0)
|
||||||
|
return true;
|
||||||
|
if (ipv6_cmp(&range[mid].begin, addr) > 0)
|
||||||
|
return geoip_bsearch6(range, addr, lo, mid);
|
||||||
|
else if (ipv6_cmp(&range[mid].end, addr) < 0)
|
||||||
|
return geoip_bsearch6(range, addr, mid + 1, hi);
|
||||||
|
|
||||||
|
WARN_ON(true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
xt_geoip_mt6(const struct sk_buff *skb, struct xt_action_param *par)
|
||||||
|
{
|
||||||
|
const struct xt_geoip_match_info *info = par->matchinfo;
|
||||||
|
const struct geoip_country_kernel *node;
|
||||||
|
const struct ipv6hdr *iph = ipv6_hdr(skb);
|
||||||
|
unsigned int i;
|
||||||
|
struct in6_addr ip;
|
||||||
|
|
||||||
|
memcpy(&ip, (info->flags & XT_GEOIP_SRC) ? &iph->saddr : &iph->daddr,
|
||||||
|
sizeof(ip));
|
||||||
|
for (i = 0; i < 4; ++i)
|
||||||
|
ip.s6_addr32[i] = ntohl(ip.s6_addr32[i]);
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
for (i = 0; i < info->count; i++) {
|
||||||
|
if ((node = info->mem[i].kernel) == NULL) {
|
||||||
|
pr_err("'%c%c' is not loaded into memory... skip it!\n",
|
||||||
|
COUNTRY(info->cc[i]));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (geoip_bsearch6(node->subnets, &ip, 0, node->count)) {
|
||||||
|
rcu_read_unlock();
|
||||||
|
return !(info->flags & XT_GEOIP_INV);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
|
return info->flags & XT_GEOIP_INV;
|
||||||
|
}
|
||||||
|
|
||||||
static bool geoip_bsearch4(const struct geoip_subnet4 *range,
|
static bool geoip_bsearch4(const struct geoip_subnet4 *range,
|
||||||
uint32_t addr, int lo, int hi)
|
uint32_t addr, int lo, int hi)
|
||||||
{
|
{
|
||||||
@@ -181,9 +266,10 @@ static int xt_geoip_mt_checkentry(const struct xt_mtchk_param *par)
|
|||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; i < info->count; i++) {
|
for (i = 0; i < info->count; i++) {
|
||||||
node = find_node(info->cc[i]);
|
node = find_node(info->cc[i], nfp2geo[par->family]);
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
node = geoip_add_node((const void __user *)(unsigned long)info->mem[i].user);
|
node = geoip_add_node((const void __user *)(unsigned long)info->mem[i].user,
|
||||||
|
nfp2geo[par->family]);
|
||||||
if (IS_ERR(node)) {
|
if (IS_ERR(node)) {
|
||||||
printk(KERN_ERR
|
printk(KERN_ERR
|
||||||
"xt_geoip: unable to load '%c%c' into memory: %ld\n",
|
"xt_geoip: unable to load '%c%c' into memory: %ld\n",
|
||||||
@@ -228,25 +314,41 @@ static void xt_geoip_mt_destroy(const struct xt_mtdtor_param *par)
|
|||||||
"xt_geoip: please report this bug to the maintainers\n");
|
"xt_geoip: please report this bug to the maintainers\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct xt_match xt_geoip_match __read_mostly = {
|
static struct xt_match xt_geoip_match[] __read_mostly = {
|
||||||
.name = "geoip",
|
{
|
||||||
.revision = 1,
|
.name = "geoip",
|
||||||
.family = NFPROTO_IPV4,
|
.revision = 1,
|
||||||
.match = xt_geoip_mt4,
|
.family = NFPROTO_IPV6,
|
||||||
.checkentry = xt_geoip_mt_checkentry,
|
.match = xt_geoip_mt6,
|
||||||
.destroy = xt_geoip_mt_destroy,
|
.checkentry = xt_geoip_mt_checkentry,
|
||||||
.matchsize = sizeof(struct xt_geoip_match_info),
|
.destroy = xt_geoip_mt_destroy,
|
||||||
.me = THIS_MODULE,
|
.matchsize = sizeof(struct xt_geoip_match_info),
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "geoip",
|
||||||
|
.revision = 1,
|
||||||
|
.family = NFPROTO_IPV4,
|
||||||
|
.match = xt_geoip_mt4,
|
||||||
|
.checkentry = xt_geoip_mt_checkentry,
|
||||||
|
.destroy = xt_geoip_mt_destroy,
|
||||||
|
.matchsize = sizeof(struct xt_geoip_match_info),
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init xt_geoip_mt_init(void)
|
static int __init xt_geoip_mt_init(void)
|
||||||
{
|
{
|
||||||
return xt_register_match(&xt_geoip_match);
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(geoip_head); ++i)
|
||||||
|
INIT_LIST_HEAD(&geoip_head[i]);
|
||||||
|
return xt_register_matches(xt_geoip_match, ARRAY_SIZE(xt_geoip_match));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit xt_geoip_mt_fini(void)
|
static void __exit xt_geoip_mt_fini(void)
|
||||||
{
|
{
|
||||||
xt_unregister_match(&xt_geoip_match);
|
xt_unregister_matches(xt_geoip_match, ARRAY_SIZE(xt_geoip_match));
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(xt_geoip_mt_init);
|
module_init(xt_geoip_mt_init);
|
||||||
|
@@ -27,6 +27,10 @@ struct geoip_subnet4 {
|
|||||||
__u32 end;
|
__u32 end;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct geoip_subnet6 {
|
||||||
|
struct in6_addr begin, end;
|
||||||
|
};
|
||||||
|
|
||||||
struct geoip_country_user {
|
struct geoip_country_user {
|
||||||
aligned_u64 subnets;
|
aligned_u64 subnets;
|
||||||
__u32 count;
|
__u32 count;
|
||||||
|
Reference in New Issue
Block a user