📄 ipchains_core.c
字号:
* chain refenced by chainptr. If position is 1 then this rule will * become the new rule one. */static int insert_in_chain(struct ip_chain *chainptr, struct ip_fwkernel *frwl, __u32 position){ struct ip_fwkernel *f = chainptr->chain; FWC_HAVE_LOCK(fwc_wlocks); /* special case if the position is number 1 */ if (position == 1) { frwl->next = chainptr->chain; if (frwl->branch) frwl->branch->refcount++; chainptr->chain = frwl; goto insert_successful; } position--; while (--position && f != NULL) f = f->next; if (f == NULL) return EINVAL; if (frwl->branch) frwl->branch->refcount++; frwl->next = f->next; f->next = frwl;insert_successful: MOD_INC_USE_COUNT; return 0;}/* This function deletes the a rule from a given rulenum and chain. * With rulenum = 1 is the first rule is deleted. */static int del_num_from_chain(struct ip_chain *chainptr, __u32 rulenum){ struct ip_fwkernel *i=chainptr->chain,*tmp; FWC_HAVE_LOCK(fwc_wlocks); if (!chainptr->chain) return ENOENT; /* Need a special case for the first rule */ if (rulenum == 1) { /* store temp to allow for freeing up of memory */ tmp = chainptr->chain; if (chainptr->chain->branch) chainptr->chain->branch->refcount--; chainptr->chain = chainptr->chain->next; kfree(tmp); /* free memory that is now unused */ } else { rulenum--; while (--rulenum && i->next ) i = i->next; if (!i->next) return ENOENT; tmp = i->next; if (i->next->branch) i->next->branch->refcount--; i->next = i->next->next; kfree(tmp); } MOD_DEC_USE_COUNT; return 0;}/* This function deletes the a rule from a given rule and chain. * The rule that is deleted is the first occursance of that rule. */static int del_rule_from_chain(struct ip_chain *chainptr, struct ip_fwkernel *frwl){ struct ip_fwkernel *ltmp,*ftmp = chainptr->chain ; int was_found; FWC_HAVE_LOCK(fwc_wlocks); /* Sure, we should compare marks, but since the `ipfwadm' * script uses it for an unholy hack... well, life is easier * this way. We also mask it out of the flags word. --PR */ for (ltmp=NULL, was_found=0; !was_found && ftmp != NULL; ltmp = ftmp,ftmp = ftmp->next) { if (ftmp->ipfw.fw_src.s_addr!=frwl->ipfw.fw_src.s_addr || ftmp->ipfw.fw_dst.s_addr!=frwl->ipfw.fw_dst.s_addr || ftmp->ipfw.fw_smsk.s_addr!=frwl->ipfw.fw_smsk.s_addr || ftmp->ipfw.fw_dmsk.s_addr!=frwl->ipfw.fw_dmsk.s_addr#if 0 || ftmp->ipfw.fw_flg!=frwl->ipfw.fw_flg#else || ((ftmp->ipfw.fw_flg & ~IP_FW_F_MARKABS) != (frwl->ipfw.fw_flg & ~IP_FW_F_MARKABS))#endif || ftmp->ipfw.fw_invflg!=frwl->ipfw.fw_invflg || ftmp->ipfw.fw_proto!=frwl->ipfw.fw_proto#if 0 || ftmp->ipfw.fw_mark!=frwl->ipfw.fw_mark#endif || ftmp->ipfw.fw_redirpt!=frwl->ipfw.fw_redirpt || ftmp->ipfw.fw_spts[0]!=frwl->ipfw.fw_spts[0] || ftmp->ipfw.fw_spts[1]!=frwl->ipfw.fw_spts[1] || ftmp->ipfw.fw_dpts[0]!=frwl->ipfw.fw_dpts[0] || ftmp->ipfw.fw_dpts[1]!=frwl->ipfw.fw_dpts[1] || ftmp->ipfw.fw_outputsize!=frwl->ipfw.fw_outputsize) { duprintf("del_rule_from_chain: mismatch:" "src:%u/%u dst:%u/%u smsk:%u/%u dmsk:%u/%u " "flg:%hX/%hX invflg:%hX/%hX proto:%u/%u " "mark:%u/%u " "ports:%hu-%hu/%hu-%hu %hu-%hu/%hu-%hu " "outputsize:%hu-%hu\n", ftmp->ipfw.fw_src.s_addr, frwl->ipfw.fw_src.s_addr, ftmp->ipfw.fw_dst.s_addr, frwl->ipfw.fw_dst.s_addr, ftmp->ipfw.fw_smsk.s_addr, frwl->ipfw.fw_smsk.s_addr, ftmp->ipfw.fw_dmsk.s_addr, frwl->ipfw.fw_dmsk.s_addr, ftmp->ipfw.fw_flg, frwl->ipfw.fw_flg, ftmp->ipfw.fw_invflg, frwl->ipfw.fw_invflg, ftmp->ipfw.fw_proto, frwl->ipfw.fw_proto, ftmp->ipfw.fw_mark, frwl->ipfw.fw_mark, ftmp->ipfw.fw_spts[0], frwl->ipfw.fw_spts[0], ftmp->ipfw.fw_spts[1], frwl->ipfw.fw_spts[1], ftmp->ipfw.fw_dpts[0], frwl->ipfw.fw_dpts[0], ftmp->ipfw.fw_dpts[1], frwl->ipfw.fw_dpts[1], ftmp->ipfw.fw_outputsize, frwl->ipfw.fw_outputsize); continue; } if (strncmp(ftmp->ipfw.fw_vianame, frwl->ipfw.fw_vianame, IFNAMSIZ)) { duprintf("del_rule_from_chain: if mismatch: %s/%s\n", ftmp->ipfw.fw_vianame, frwl->ipfw.fw_vianame); continue; } if (ftmp->branch != frwl->branch) { duprintf("del_rule_from_chain: branch mismatch: " "%s/%s\n", ftmp->branch?ftmp->branch->label:"(null)", frwl->branch?frwl->branch->label:"(null)"); continue; } if (ftmp->branch == NULL && ftmp->simplebranch != frwl->simplebranch) { duprintf("del_rule_from_chain: simplebranch mismatch: " "%i/%i\n", ftmp->simplebranch, frwl->simplebranch); continue; } was_found = 1; if (ftmp->branch) ftmp->branch->refcount--; if (ltmp) ltmp->next = ftmp->next; else chainptr->chain = ftmp->next; kfree(ftmp); MOD_DEC_USE_COUNT; break; } if (was_found) return 0; else { duprintf("del_rule_from_chain: no matching rule found\n"); return EINVAL; }}/* This function takes the label of a chain and deletes the first * chain with that name. No special cases required for the built in * chains as they have their refcount initilised to 1 so that they are * never deleted. */static int del_chain(ip_chainlabel label){ struct ip_chain *tmp,*tmp2; FWC_HAVE_LOCK(fwc_wlocks); /* Corner case: return EBUSY not ENOENT for first elem ("input") */ if (strcmp(label, ip_fw_chains->label) == 0) return EBUSY; for (tmp = ip_fw_chains; tmp->next; tmp = tmp->next) if(strcmp(tmp->next->label,label) == 0) break; tmp2 = tmp->next; if (!tmp2) return ENOENT; if (tmp2->refcount) return EBUSY; if (tmp2->chain) return ENOTEMPTY; tmp->next = tmp2->next; kfree(tmp2); MOD_DEC_USE_COUNT; return 0;}/* This is a function to initilise a chain. Built in rules start with * refcount = 1 so that they cannot be deleted. User defined rules * start with refcount = 0 so they can be deleted. */static struct ip_chain *ip_init_chain(ip_chainlabel name, __u32 ref, int policy){ unsigned int i; struct ip_chain *label = kmalloc(SIZEOF_STRUCT_IP_CHAIN, GFP_KERNEL); if (label == NULL) panic("Can't kmalloc for firewall chains.\n"); strcpy(label->label,name); label->next = NULL; label->chain = NULL; label->refcount = ref; label->policy = policy; for (i = 0; i < smp_num_cpus*2; i++) { label->reent[i].counters.pcnt = label->reent[i].counters.bcnt = 0; label->reent[i].prevchain = NULL; label->reent[i].prevrule = NULL; } return label;}/* This is a function for reating a new chain. The chains is not * created if a chain of the same name already exists */static int create_chain(ip_chainlabel label){ struct ip_chain *tmp; if (!check_label(label)) return EINVAL; FWC_HAVE_LOCK(fwc_wlocks); for (tmp = ip_fw_chains; tmp->next; tmp = tmp->next) if (strcmp(tmp->label,label) == 0) return EEXIST; if (strcmp(tmp->label,label) == 0) return EEXIST; tmp->next = ip_init_chain(label, 0, FW_SKIP); /* refcount is * zero since this is a * user defined chain * * and therefore can be * deleted */ MOD_INC_USE_COUNT; return 0;}/* This function simply changes the policy on one of the built in * chains. checking must be done before this is call to ensure that * chainptr is pointing to one of the three possible chains */static int change_policy(struct ip_chain *chainptr, int policy){ FWC_HAVE_LOCK(fwc_wlocks); chainptr->policy = policy; return 0;}/* This function takes an ip_fwuser and converts it to a ip_fwkernel. It also * performs some checks in the structure. */static struct ip_fwkernel *convert_ipfw(struct ip_fwuser *fwuser, int *errno){ struct ip_fwkernel *fwkern; if ( (fwuser->ipfw.fw_flg & ~IP_FW_F_MASK) != 0 ) { duprintf("convert_ipfw: undefined flag bits set (flags=%x)\n", fwuser->ipfw.fw_flg); *errno = EINVAL; return NULL; }#ifdef DEBUG_IP_FIREWALL_USER /* These are sanity checks that don't really matter. * We can get rid of these once testing is complete. */ if ((fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN) && ((fwuser->ipfw.fw_invflg & IP_FW_INV_PROTO) || fwuser->ipfw.fw_proto != IPPROTO_TCP)) { duprintf("convert_ipfw: TCP SYN flag set but proto != TCP!\n"); *errno = EINVAL; return NULL; } if (strcmp(fwuser->label, IP_FW_LABEL_REDIRECT) != 0 && fwuser->ipfw.fw_redirpt != 0) { duprintf("convert_ipfw: Target not REDIR but redirpt != 0!\n"); *errno = EINVAL; return NULL; } if ((!(fwuser->ipfw.fw_flg & IP_FW_F_FRAG) && (fwuser->ipfw.fw_invflg & IP_FW_INV_FRAG)) || (!(fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN) && (fwuser->ipfw.fw_invflg & IP_FW_INV_SYN))) { duprintf("convert_ipfw: Can't have INV flag if flag unset!\n"); *errno = EINVAL; return NULL; } if (((fwuser->ipfw.fw_invflg & IP_FW_INV_SRCPT) && fwuser->ipfw.fw_spts[0] == 0 && fwuser->ipfw.fw_spts[1] == 0xFFFF) || ((fwuser->ipfw.fw_invflg & IP_FW_INV_DSTPT) && fwuser->ipfw.fw_dpts[0] == 0 && fwuser->ipfw.fw_dpts[1] == 0xFFFF) || ((fwuser->ipfw.fw_invflg & IP_FW_INV_VIA) && (fwuser->ipfw.fw_vianame)[0] == '\0') || ((fwuser->ipfw.fw_invflg & IP_FW_INV_SRCIP) && fwuser->ipfw.fw_smsk.s_addr == 0) || ((fwuser->ipfw.fw_invflg & IP_FW_INV_DSTIP) && fwuser->ipfw.fw_dmsk.s_addr == 0)) { duprintf("convert_ipfw: INV flag makes rule unmatchable!\n"); *errno = EINVAL; return NULL; } if ((fwuser->ipfw.fw_flg & IP_FW_F_FRAG) && !(fwuser->ipfw.fw_invflg & IP_FW_INV_FRAG) && (fwuser->ipfw.fw_spts[0] != 0 || fwuser->ipfw.fw_spts[1] != 0xFFFF || fwuser->ipfw.fw_dpts[0] != 0 || fwuser->ipfw.fw_dpts[1] != 0xFFFF || (fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN))) { duprintf("convert_ipfw: Can't test ports or SYN with frag!\n"); *errno = EINVAL; return NULL; }#endif if ((fwuser->ipfw.fw_spts[0] != 0 || fwuser->ipfw.fw_spts[1] != 0xFFFF || fwuser->ipfw.fw_dpts[0] != 0 || fwuser->ipfw.fw_dpts[1] != 0xFFFF) && ((fwuser->ipfw.fw_invflg & IP_FW_INV_PROTO) || (fwuser->ipfw.fw_proto != IPPROTO_TCP && fwuser->ipfw.fw_proto != IPPROTO_UDP && fwuser->ipfw.fw_proto != IPPROTO_ICMP))) { duprintf("convert_ipfw: Can only test ports for TCP/UDP/ICMP!\n"); *errno = EINVAL; return NULL; } fwkern = kmalloc(SIZEOF_STRUCT_IP_FW_KERNEL, GFP_KERNEL); if (!fwkern) { duprintf("convert_ipfw: kmalloc failed!\n"); *errno = ENOMEM; return NULL; } memcpy(&fwkern->ipfw,&fwuser->ipfw,sizeof(struct ip_fw)); if (!find_special(fwuser->label, &fwkern->simplebranch)) { fwkern->branch = find_label(fwuser->label); if (!fwkern->branch) { duprintf("convert_ipfw: chain doesn't exist `%s'.\n", fwuser->label); kfree(fwkern); *errno = ENOENT; return NULL; } else if (fwkern->branch == IP_FW_INPUT_CHAIN || fwkern->branch == IP_FW_FORWARD_CHAIN || fwkern->branch == IP_FW_OUTPUT_CHAIN) { duprintf("convert_ipfw: Can't branch to builtin chain `%s'.\n", fwuser->label); kfree(fwkern); *errno = ENOENT; return NULL; } } else fwkern->branch = NULL; memset(fwkern->counters, 0, sizeof(struct ip_counters)*NUM_SLOTS); /* Handle empty vianame by making it a wildcard */ if ((fwkern->ipfw.fw_vianame)[0] == '\0') fwkern->ipfw.fw_flg |= IP_FW_F_WILDIF; fwkern->next = NULL; return fwkern;}int ip_fw_ctl(int cmd, void *m, int len){ int ret; struct ip_chain *chain; unsigned long flags; FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags); switch (cmd) { case IP_FW_FLUSH: if (len != sizeof(ip_chainlabel) || !check_label(m)) ret = EINVAL; else if ((chain = find_label(m)) == NULL) ret = ENOENT; else ret = clear_fw_chain(chain); break; case IP_FW_ZERO: if (len != sizeof(ip_chainlabel) || !check_label(m)) ret = EINVAL; else if ((chain = find_label(m)) == NULL) ret = ENOENT; else ret = zero_fw_chain(chain); break; case IP_FW_CHECK: { struct ip_fwtest *new = m; struct iphdr *ip; /* Don't need write lock. */ FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags); if (len != sizeof(struct ip_fwtest) || !check_label(m)) return EINVAL; /* Need readlock to do find_label */ FWC_READ_LOCK(&ip_fw_lock); if ((chain = find_label(new->fwt_label)) == NULL) ret = ENOENT; else { ip = &(new->fwt_packet.fwp_iph); if (ip->ihl != sizeof(struct iphdr) / sizeof(int)) { duprintf("ip_fw_ctl: ip->ihl=%d, want %d\n", ip->ihl, sizeof(struct iphdr) / sizeof(int)); ret = EINVAL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -