📄 ipt_recent.c
字号:
if (matchsize != IPT_ALIGN(sizeof(struct ipt_recent_info))) return 0; /* seconds and hit_count only valid for CHECK/UPDATE */ if(info->check_set & IPT_RECENT_SET) { flag++; if(info->seconds || info->hit_count) return 0; } if(info->check_set & IPT_RECENT_REMOVE) { flag++; if(info->seconds || info->hit_count) return 0; } if(info->check_set & IPT_RECENT_CHECK) flag++; if(info->check_set & IPT_RECENT_UPDATE) flag++; /* One and only one of these should ever be set */ if(flag != 1) return 0; /* Name must be set to something */ if(!info->name || !info->name[0]) return 0; /* Things look good, create a list for this if it does not exist */ /* Lock the linked list while we play with it */ spin_lock_bh(&recent_lock); /* Look for an entry with this name already created */ /* Finds the end of the list and the entry before the end if current name does not exist */ find_table = r_tables; while( (last_table = find_table) && strncmp(info->name,find_table->name,IPT_RECENT_NAME_LEN) && (find_table = find_table->next) ); /* If a table already exists just increment the count on that table and return */ if(find_table) { #ifdef DEBUG if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: table found (%s), incrementing count.\n",info->name);#endif find_table->count++; spin_unlock_bh(&recent_lock); return 1; } spin_unlock_bh(&recent_lock); /* Table with this name not found */ /* Allocate memory for new linked list item */#ifdef DEBUG if(debug) { printk(KERN_INFO RECENT_NAME ": checkentry: no table found (%s)\n",info->name); printk(KERN_INFO RECENT_NAME ": checkentry: Allocationg %d for link-list entry.\n",sizeof(struct recent_ip_tables)); }#endif curr_table = vmalloc(sizeof(struct recent_ip_tables)); if(curr_table == NULL) return 0; spin_lock_init(&curr_table->list_lock); curr_table->next = NULL; curr_table->count = 1; curr_table->time_pos = 0; strncpy(curr_table->name,info->name,IPT_RECENT_NAME_LEN); curr_table->name[IPT_RECENT_NAME_LEN-1] = '\0'; /* Allocate memory for this table and the list of packets in each entry. */#ifdef DEBUG if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: Allocating %d for table (%s).\n", sizeof(struct recent_ip_list)*ip_list_tot, info->name);#endif curr_table->table = vmalloc(sizeof(struct recent_ip_list)*ip_list_tot); if(curr_table->table == NULL) { vfree(curr_table); return 0; } memset(curr_table->table,0,sizeof(struct recent_ip_list)*ip_list_tot);#ifdef DEBUG if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: Allocating %d for pkt_list.\n", sizeof(unsigned long)*ip_pkt_list_tot*ip_list_tot);#endif hold = vmalloc(sizeof(unsigned long)*ip_pkt_list_tot*ip_list_tot);#ifdef DEBUG if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: After pkt_list allocation.\n");#endif if(hold == NULL) { printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for pkt_list.\n"); vfree(curr_table->table); vfree(curr_table); return 0; } for(c = 0; c < ip_list_tot; c++) { curr_table->table[c].last_pkts = hold + c*ip_pkt_list_tot; } /* Allocate memory for the hash table */#ifdef DEBUG if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: Allocating %d for hash_table.\n", sizeof(int)*ip_list_hash_size);#endif curr_table->hash_table = vmalloc(sizeof(int)*ip_list_hash_size); if(!curr_table->hash_table) { printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for hash_table.\n"); vfree(hold); vfree(curr_table->table); vfree(curr_table); return 0; } for(c = 0; c < ip_list_hash_size; c++) { curr_table->hash_table[c] = -1; } /* Allocate memory for the time info */#ifdef DEBUG if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: Allocating %d for time_info.\n", sizeof(struct time_info_list)*ip_list_tot);#endif curr_table->time_info = vmalloc(sizeof(struct time_info_list)*ip_list_tot); if(!curr_table->time_info) { printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for time_info.\n"); vfree(curr_table->hash_table); vfree(hold); vfree(curr_table->table); vfree(curr_table); return 0; } for(c = 0; c < ip_list_tot; c++) { curr_table->time_info[c].position = c; curr_table->time_info[c].time = 0; } /* Put the new table in place */ spin_lock_bh(&recent_lock); find_table = r_tables; while( (last_table = find_table) && strncmp(info->name,find_table->name,IPT_RECENT_NAME_LEN) && (find_table = find_table->next) ); /* If a table already exists just increment the count on that table and return */ if(find_table) { find_table->count++; spin_unlock_bh(&recent_lock);#ifdef DEBUG if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: table found (%s), created by other process.\n",info->name);#endif vfree(curr_table->time_info); vfree(curr_table->hash_table); vfree(hold); vfree(curr_table->table); vfree(curr_table); return 1; } if(!last_table) r_tables = curr_table; else last_table->next = curr_table; spin_unlock_bh(&recent_lock);#ifdef CONFIG_PROC_FS /* Create our proc 'status' entry. */ curr_table->status_proc = create_proc_entry(curr_table->name, ip_list_perms, proc_net_ipt_recent); if (!curr_table->status_proc) { printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for /proc entry.\n"); /* Destroy the created table */ spin_lock_bh(&recent_lock); last_table = NULL; curr_table = r_tables; if(!curr_table) {#ifdef DEBUG if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() create_proc failed, no tables.\n");#endif spin_unlock_bh(&recent_lock); return 0; } while( strncmp(info->name,curr_table->name,IPT_RECENT_NAME_LEN) && (last_table = curr_table) && (curr_table = curr_table->next) ); if(!curr_table) {#ifdef DEBUG if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() create_proc failed, table already destroyed.\n");#endif spin_unlock_bh(&recent_lock); return 0; } if(last_table) last_table->next = curr_table->next; else r_tables = curr_table->next; spin_unlock_bh(&recent_lock); vfree(curr_table->time_info); vfree(curr_table->hash_table); vfree(hold); vfree(curr_table->table); vfree(curr_table); return 0; } curr_table->status_proc->owner = THIS_MODULE; curr_table->status_proc->data = curr_table; wmb(); curr_table->status_proc->read_proc = ip_recent_get_info; curr_table->status_proc->write_proc = ip_recent_ctrl;#endif /* CONFIG_PROC_FS */#ifdef DEBUG if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() left.\n");#endif return 1;}/* This function is called in the event that a rule matching this module is * removed. * When this happens we need to check if there are no other rules matching * the table given. If that is the case then we remove the table and clean * up its memory. */static voiddestroy(void *matchinfo, unsigned int matchsize){ const struct ipt_recent_info *info = matchinfo; struct recent_ip_tables *curr_table, *last_table;#ifdef DEBUG if(debug) printk(KERN_INFO RECENT_NAME ": destroy() entered.\n");#endif if(matchsize != IPT_ALIGN(sizeof(struct ipt_recent_info))) return; /* Lock the linked list while we play with it */ spin_lock_bh(&recent_lock); /* Look for an entry with this name already created */ /* Finds the end of the list and the entry before the end if current name does not exist */ last_table = NULL; curr_table = r_tables; if(!curr_table) { #ifdef DEBUG if(debug) printk(KERN_INFO RECENT_NAME ": destroy() No tables found, leaving.\n");#endif spin_unlock_bh(&recent_lock); return; } while( strncmp(info->name,curr_table->name,IPT_RECENT_NAME_LEN) && (last_table = curr_table) && (curr_table = curr_table->next) ); /* If a table does not exist then do nothing and return */ if(!curr_table) { #ifdef DEBUG if(debug) printk(KERN_INFO RECENT_NAME ": destroy() table not found, leaving.\n");#endif spin_unlock_bh(&recent_lock); return; } curr_table->count--; /* If count is still non-zero then there are still rules referenceing it so we do nothing */ if(curr_table->count) { #ifdef DEBUG if(debug) printk(KERN_INFO RECENT_NAME ": destroy() table found, non-zero count, leaving.\n");#endif spin_unlock_bh(&recent_lock); return; }#ifdef DEBUG if(debug) printk(KERN_INFO RECENT_NAME ": destroy() table found, zero count, removing.\n");#endif /* Count must be zero so we remove this table from the list */ if(last_table) last_table->next = curr_table->next; else r_tables = curr_table->next; spin_unlock_bh(&recent_lock); /* lock to make sure any late-runners still using this after we removed it from * the list finish up then remove everything */ spin_lock_bh(&curr_table->list_lock); spin_unlock_bh(&curr_table->list_lock);#ifdef CONFIG_PROC_FS if(curr_table->status_proc) remove_proc_entry(curr_table->name,proc_net_ipt_recent);#endif /* CONFIG_PROC_FS */ vfree(curr_table->table[0].last_pkts); vfree(curr_table->table); vfree(curr_table->hash_table); vfree(curr_table->time_info); vfree(curr_table);#ifdef DEBUG if(debug) printk(KERN_INFO RECENT_NAME ": destroy() left.\n");#endif return;}/* This is the structure we pass to ipt_register to register our * module with iptables. */static struct ipt_match recent_match = { .name = "recent", .match = &match, .checkentry = &checkentry, .destroy = &destroy, .me = THIS_MODULE};/* Kernel module initialization. */static int __init init(void){ int err, count; printk(version);#ifdef CONFIG_PROC_FS proc_net_ipt_recent = proc_mkdir("ipt_recent",proc_net); if(!proc_net_ipt_recent) return -ENOMEM;#endif if(ip_list_hash_size && ip_list_hash_size <= ip_list_tot) { printk(KERN_WARNING RECENT_NAME ": ip_list_hash_size too small, resetting to default.\n"); ip_list_hash_size = 0; } if(!ip_list_hash_size) { ip_list_hash_size = ip_list_tot*3; count = 2*2; while(ip_list_hash_size > count) count = count*2; ip_list_hash_size = count; }#ifdef DEBUG if(debug) printk(KERN_INFO RECENT_NAME ": ip_list_hash_size: %d\n",ip_list_hash_size);#endif err = ipt_register_match(&recent_match); if (err) remove_proc_entry("ipt_recent", proc_net); return err;}/* Kernel module destruction. */static void __exit fini(void){ ipt_unregister_match(&recent_match); remove_proc_entry("ipt_recent",proc_net);}/* Register our module with the kernel. */module_init(init);module_exit(fini);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -