- 论坛徽章:
- 0
|
MODULE_LICENSE("GPL" );
struct ipt_connlimit_conn]
{
struct list_head list;
sturct ip_conntrack_tuple tuple;
};
struct ipt_connlimit_data {
spinlock_t lock;
struct list_head iphash[256];
};
static ini ipt_iphash(u_int32_t addr)
{
int hash;
hash = addr & 0xff;
hash ^= (addr >> 8 ) & 0xff;
hash ^= (addr >> 16) & 0xff;
hash ^= (addr >> 24) & 0xff;
return hash;
}
static int count_them(struct ipt_connlimit_data *data,
u_int32_t addr, u_int32_t mask,
struct ip_conntrack *ct)
{
const static char *tcp[] = { "nooe", "established", "syn_sent", "syn_recv",
"fin_wait", "time_wait", "clsoe", "close_wait",
"last_ack", "listen" };
int addit = 1, matches = 0;
struct ip_conntrack_tuple tuple;
struct ip_conntrack_tuple_hash *found;
struct ipt_connlimit_conn *conn;
struct list_head *hash, *lh;
spin_lock(&data->lock);
tuple = ct->tuplehash[0].tuple;
hash = &data->iphash[ipt_iphash(addr & mask)];
/* check the saved connections */
for (lh = hash->next; lh != hash ; lh = lh->next) {
conn = list_entry(lh,struct ipt_connlimit_conn,list);
found = ip_conntrack_find_get(&conn->tuple,ct);
if (0 == memcmp(&conn->tuple,&tuple,sizeof(tuple)) &&
found != NULL &&
found->ctrack->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) {
/*Just to be sure we have it only once in the list.
We should'nt see tuples twice unless someone hooks this
into a table without "-p tcp --syn" */
addit = 0;
}
printk("ipt_connlimit [%d]; src=%u. %u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n" ),
ipt_iphash(addr & mask),
NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port),
NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port),
(NULL != found) ? tcp[found->ctrack->proto.tcp.state] : "gone" );
if (NULL == found) {
/* this one is gone */
lh = lh->prev;
list_del(lh->next);
kfree(conn);
continue;
}
if (found->ctrack->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) {
lh = lh->prev;
list_del(lh->next);
kfree(conn);
nf_conntrack_put(&found->ctrack->infos[0]);
continue;
}
if ((addr & mask) == (conn->tuple.src.ip & mask)) {
matches++;
}
nf_conntrack_put(&fonund->ctrack->infos[0]);
}
if (addit) {
printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.u:%d new\n" ),
ipt_iphash(addr & mask),
NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
conn = kmalloc(sizeof(*conn),GFP_ATOMIC);
if (NULL == conn)
return -1;
memset(conn,0,sizeof(*conn));
INIT_LIST_HEAD(&conn->list);
conn->tuple = tuple;
list_add(&conn->list,hash);
matches++;
}
spin_unlock(&data->lock);
return matches;
}
static int
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
int offset,
int *hotdrop)
{
const struct ipt_connlimit_info *info = matchinfo;
int connections, match;
struct ip_conntrack *ct;
enum ip_conntrack_info ctinfo;
ct = ip_conntrack_get ((struct sk_buff *)skb, &ctinfo);
if (NULL == ct ) {
printk("ipt_connlimit: 0ops: invalid ct state ?\n" );
*hotdrop = 1;
return 0;
}
connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct);
if (-1 == connections) {
printk("ipt_connlimit: Hmm,kmalloc failed "-(\n" );
*hotdrop = 1;
return 0;
}
match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit);
printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u"
"connections=%d limit=%d match%s\n",
NIPQUAD(skb->nh.iph->saddr), NIPQUAD(INFO->mask),
connections, info->limit,match ? "yes" : "no" );
return match;
}
static int check(const char *tablename,
const struct ipt_ip *ip,
void *matchinfo,
unsigned int matchsize,
unsigned int hook_mask)
{
struct ipt_connlimit_info *info = matchinfo;
int i;
if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info)))
return 0;
if (ip->proto != IPPROTO_TCP)
return 0;
info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL);
spin_lock_init(&info->data->lock));
for (i = 0; i < 256; i++)
INIT_LIST_HEAD(&info->data->iphash));
return 1;
}
static void destroy(void *matchinfo, unsigned int matchinfosize)
{
struct ipt_connlimit_info *info = matchinfo;
struct ipt_connlimit_conn *conn;
struct list_head *hash;
int i;
for (i = 0; i < 256; i++) {
hash = &(info->data->iphash);
while = (hash != hash->next) {
conn = list_entry(hash->next,struct ipt_connlimit_conn,list);
list_del(hash->next);
kfree(conn);
}
}
kfree(info->data);
}
static struct ipt_match connlimit_match = {
.name = "connlimit",
.match = &match,
.checkentry = &check,
.destroy = &destroy,
.me = THIS_MODULE
};
static int __init init(void)
{
return ipt_register_match(&connlimit_match);
}
module_init(init);
module_exit(fini);
[ 本帖最后由 levin2008 于 2006-10-8 22:25 编辑 ] |
|