📄 ipt_clusterip.c
字号:
return 0; } if (cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP && cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT && cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT_DPT) { printk(KERN_WARNING "CLUSTERIP: unknown mode `%u'\n", cipinfo->hash_mode); return 0; } if (e->ip.dmsk.s_addr != 0xffffffff || e->ip.dst.s_addr == 0) { printk(KERN_ERR "CLUSTERIP: Please specify destination IP\n"); return 0; } /* FIXME: further sanity checks */ config = clusterip_config_find_get(e->ip.dst.s_addr, 1); if (config) { if (cipinfo->config != NULL) { /* Case A: This is an entry that gets reloaded, since * it still has a cipinfo->config pointer. Simply * increase the entry refcount and return */ if (cipinfo->config != config) { printk(KERN_ERR "CLUSTERIP: Reloaded entry " "has invalid config pointer!\n"); return 0; } clusterip_config_entry_get(cipinfo->config); } else { /* Case B: This is a new rule referring to an existing * clusterip config. */ cipinfo->config = config; clusterip_config_entry_get(cipinfo->config); } } else { /* Case C: This is a completely new clusterip config */ if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) { printk(KERN_WARNING "CLUSTERIP: no config found for %u.%u.%u.%u, need 'new'\n", NIPQUAD(e->ip.dst.s_addr)); return 0; } else { struct net_device *dev; if (e->ip.iniface[0] == '\0') { printk(KERN_WARNING "CLUSTERIP: Please specify an interface name\n"); return 0; } dev = dev_get_by_name(e->ip.iniface); if (!dev) { printk(KERN_WARNING "CLUSTERIP: no such interface %s\n", e->ip.iniface); return 0; } config = clusterip_config_init(cipinfo, e->ip.dst.s_addr, dev); if (!config) { printk(KERN_WARNING "CLUSTERIP: cannot allocate config\n"); dev_put(dev); return 0; } dev_mc_add(config->dev,config->clustermac, ETH_ALEN, 0); } cipinfo->config = config; } return 1;}/* drop reference count of cluster config when rule is deleted */static void destroy(void *matchinfo, unsigned int matchinfosize){ struct ipt_clusterip_tgt_info *cipinfo = matchinfo; /* if no more entries are referencing the config, remove it * from the list and destroy the proc entry */ clusterip_config_entry_put(cipinfo->config); clusterip_config_put(cipinfo->config);}static struct ipt_target clusterip_tgt = { .name = "CLUSTERIP", .target = &target, .checkentry = &checkentry, .destroy = &destroy, .me = THIS_MODULE};/*********************************************************************** * ARP MANGLING CODE ***********************************************************************//* hardcoded for 48bit ethernet and 32bit ipv4 addresses */struct arp_payload { u_int8_t src_hw[ETH_ALEN]; u_int32_t src_ip; u_int8_t dst_hw[ETH_ALEN]; u_int32_t dst_ip;} __attribute__ ((packed));#ifdef CLUSTERIP_DEBUGstatic void arp_print(struct arp_payload *payload) {#define HBUFFERLEN 30 char hbuffer[HBUFFERLEN]; int j,k; const char hexbuf[]= "0123456789abcdef"; for (k=0, j=0; k < HBUFFERLEN-3 && j < ETH_ALEN; j++) { hbuffer[k++]=hexbuf[(payload->src_hw[j]>>4)&15]; hbuffer[k++]=hexbuf[payload->src_hw[j]&15]; hbuffer[k++]=':'; } hbuffer[--k]='\0'; printk("src %u.%u.%u.%u@%s, dst %u.%u.%u.%u\n", NIPQUAD(payload->src_ip), hbuffer, NIPQUAD(payload->dst_ip));}#endifstatic unsigned intarp_mangle(unsigned int hook, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)){ struct arphdr *arp = (*pskb)->nh.arph; struct arp_payload *payload; struct clusterip_config *c; /* we don't care about non-ethernet and non-ipv4 ARP */ if (arp->ar_hrd != htons(ARPHRD_ETHER) || arp->ar_pro != htons(ETH_P_IP) || arp->ar_pln != 4 || arp->ar_hln != ETH_ALEN) return NF_ACCEPT; /* we only want to mangle arp requests and replies */ if (arp->ar_op != htons(ARPOP_REPLY) && arp->ar_op != htons(ARPOP_REQUEST)) return NF_ACCEPT; payload = (void *)(arp+1); /* if there is no clusterip configuration for the arp reply's * source ip, we don't want to mangle it */ c = clusterip_config_find_get(payload->src_ip, 0); if (!c) return NF_ACCEPT; /* normally the linux kernel always replies to arp queries of * addresses on different interfacs. However, in the CLUSTERIP case * this wouldn't work, since we didn't subscribe the mcast group on * other interfaces */ if (c->dev != out) { DEBUGP("CLUSTERIP: not mangling arp reply on different " "interface: cip'%s'-skb'%s'\n", c->dev->name, out->name); clusterip_config_put(c); return NF_ACCEPT; } /* mangle reply hardware address */ memcpy(payload->src_hw, c->clustermac, arp->ar_hln);#ifdef CLUSTERIP_DEBUG DEBUGP(KERN_DEBUG "CLUSTERIP mangled arp reply: "); arp_print(payload);#endif clusterip_config_put(c); return NF_ACCEPT;}static struct nf_hook_ops cip_arp_ops = { .hook = arp_mangle, .pf = NF_ARP, .hooknum = NF_ARP_OUT, .priority = -1};/*********************************************************************** * PROC DIR HANDLING ***********************************************************************/#ifdef CONFIG_PROC_FSstruct clusterip_seq_position { unsigned int pos; /* position */ unsigned int weight; /* number of bits set == size */ unsigned int bit; /* current bit */ unsigned long val; /* current value */};static void *clusterip_seq_start(struct seq_file *s, loff_t *pos){ struct proc_dir_entry *pde = s->private; struct clusterip_config *c = pde->data; unsigned int weight; u_int32_t local_nodes; struct clusterip_seq_position *idx; /* FIXME: possible race */ local_nodes = c->local_nodes; weight = hweight32(local_nodes); if (*pos >= weight) return NULL; idx = kmalloc(sizeof(struct clusterip_seq_position), GFP_KERNEL); if (!idx) return ERR_PTR(-ENOMEM); idx->pos = *pos; idx->weight = weight; idx->bit = ffs(local_nodes); idx->val = local_nodes; clear_bit(idx->bit - 1, &idx->val); return idx;}static void *clusterip_seq_next(struct seq_file *s, void *v, loff_t *pos){ struct clusterip_seq_position *idx = (struct clusterip_seq_position *)v; *pos = ++idx->pos; if (*pos >= idx->weight) { kfree(v); return NULL; } idx->bit = ffs(idx->val); clear_bit(idx->bit - 1, &idx->val); return idx;}static void clusterip_seq_stop(struct seq_file *s, void *v){ kfree(v);}static int clusterip_seq_show(struct seq_file *s, void *v){ struct clusterip_seq_position *idx = (struct clusterip_seq_position *)v; if (idx->pos != 0) seq_putc(s, ','); seq_printf(s, "%u", idx->bit); if (idx->pos == idx->weight - 1) seq_putc(s, '\n'); return 0;}static struct seq_operations clusterip_seq_ops = { .start = clusterip_seq_start, .next = clusterip_seq_next, .stop = clusterip_seq_stop, .show = clusterip_seq_show,};static int clusterip_proc_open(struct inode *inode, struct file *file){ int ret = seq_open(file, &clusterip_seq_ops); if (!ret) { struct seq_file *sf = file->private_data; struct proc_dir_entry *pde = PDE(inode); struct clusterip_config *c = pde->data; sf->private = pde; clusterip_config_get(c); } return ret;}static int clusterip_proc_release(struct inode *inode, struct file *file){ struct proc_dir_entry *pde = PDE(inode); struct clusterip_config *c = pde->data; int ret; ret = seq_release(inode, file); if (!ret) clusterip_config_put(c); return ret;}static ssize_t clusterip_proc_write(struct file *file, const char __user *input, size_t size, loff_t *ofs){#define PROC_WRITELEN 10 char buffer[PROC_WRITELEN+1]; struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode); struct clusterip_config *c = pde->data; unsigned long nodenum; if (copy_from_user(buffer, input, PROC_WRITELEN)) return -EFAULT; if (*buffer == '+') { nodenum = simple_strtoul(buffer+1, NULL, 10); if (clusterip_add_node(c, nodenum)) return -ENOMEM; } else if (*buffer == '-') { nodenum = simple_strtoul(buffer+1, NULL,10); if (clusterip_del_node(c, nodenum)) return -ENOENT; } else return -EIO; return size;}static struct file_operations clusterip_proc_fops = { .owner = THIS_MODULE, .open = clusterip_proc_open, .read = seq_read, .write = clusterip_proc_write, .llseek = seq_lseek, .release = clusterip_proc_release,};#endif /* CONFIG_PROC_FS */static int init_or_cleanup(int fini){ int ret; if (fini) goto cleanup; if (ipt_register_target(&clusterip_tgt)) { ret = -EINVAL; goto cleanup_none; } if (nf_register_hook(&cip_arp_ops) < 0) { ret = -EINVAL; goto cleanup_target; }#ifdef CONFIG_PROC_FS clusterip_procdir = proc_mkdir("ipt_CLUSTERIP", proc_net); if (!clusterip_procdir) { printk(KERN_ERR "CLUSTERIP: Unable to proc dir entry\n"); ret = -ENOMEM; goto cleanup_hook; }#endif /* CONFIG_PROC_FS */ printk(KERN_NOTICE "ClusterIP Version %s loaded successfully\n", CLUSTERIP_VERSION); return 0;cleanup: printk(KERN_NOTICE "ClusterIP Version %s unloading\n", CLUSTERIP_VERSION);#ifdef CONFIG_PROC_FS remove_proc_entry(clusterip_procdir->name, clusterip_procdir->parent);#endifcleanup_hook: nf_unregister_hook(&cip_arp_ops);cleanup_target: ipt_unregister_target(&clusterip_tgt);cleanup_none: return -EINVAL;}static int __init init(void){ return init_or_cleanup(0);}static void __exit fini(void){ init_or_cleanup(1);}module_init(init);module_exit(fini);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -