📄 ip_fw.c
字号:
break; } else { fcpl = fcp; } } flush_rule_ptrs(); splx(s); return (0);}static intdel_entry(struct ip_fw_head *chainptr, u_short number){ struct ip_fw_chain *fcp; fcp = LIST_FIRST(chainptr); if (number != (u_short)-1) { for (; fcp; fcp = LIST_NEXT(fcp, chain)) { if (fcp->rule->fw_number == number) { int s; /* prevent access to rules while removing them */ s = splnet(); while (fcp && fcp->rule->fw_number == number) { struct ip_fw_chain *next; next = LIST_NEXT(fcp, chain); LIST_REMOVE(fcp, chain);#ifdef DUMMYNET dn_rule_delete(fcp) ;#endif flush_rule_ptrs(); free(fcp->rule, M_IPFW); free(fcp, M_IPFW); fcp = next; } splx(s); return 0; } } } return (EINVAL);}static intzero_entry(struct ip_fw *frwl){ struct ip_fw_chain *fcp; int s, cleared; if (frwl == 0) { s = splnet(); for (fcp = LIST_FIRST(&ip_fw_chain); fcp; fcp = LIST_NEXT(fcp, chain)) { fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0; fcp->rule->timestamp = 0; } splx(s); } else { cleared = 0; /* * It's possible to insert multiple chain entries with the * same number, so we don't stop after finding the first * match if zeroing a specific entry. */ for (fcp = LIST_FIRST(&ip_fw_chain); fcp; fcp = LIST_NEXT(fcp, chain)) if (frwl->fw_number == fcp->rule->fw_number) { s = splnet(); while (fcp && frwl->fw_number == fcp->rule->fw_number) { fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0; fcp->rule->timestamp = 0; fcp = LIST_NEXT(fcp, chain); } splx(s); cleared = 1; break; } if (!cleared) /* we didn't find any matching rules */ return (EINVAL); } if (fw_verbose) { if (frwl) printf("ipfw: Entry %d cleared.\n", frwl->fw_number); else printf("ipfw: Accounting cleared.\n"); } return (0);}static intcheck_ipfw_struct(struct ip_fw *frwl){ /* Check for invalid flag bits */ if ((frwl->fw_flg & ~IP_FW_F_MASK) != 0) { dprintf(("%s undefined flag bits set (flags=%x)\n", err_prefix, frwl->fw_flg)); return (EINVAL); } /* Must apply to incoming or outgoing (or both) */ if (!(frwl->fw_flg & (IP_FW_F_IN | IP_FW_F_OUT))) { dprintf(("%s neither in nor out\n", err_prefix)); return (EINVAL); } /* Empty interface name is no good */ if (((frwl->fw_flg & IP_FW_F_IIFNAME) && !*frwl->fw_in_if.fu_via_if.name) || ((frwl->fw_flg & IP_FW_F_OIFNAME) && !*frwl->fw_out_if.fu_via_if.name)) { dprintf(("%s empty interface name\n", err_prefix)); return (EINVAL); } /* Sanity check interface matching */ if ((frwl->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) { ; /* allow "via" backwards compatibility */ } else if ((frwl->fw_flg & IP_FW_F_IN) && (frwl->fw_flg & IP_FW_F_OIFACE)) { dprintf(("%s outgoing interface check on incoming\n", err_prefix)); return (EINVAL); } /* Sanity check port ranges */ if ((frwl->fw_flg & IP_FW_F_SRNG) && IP_FW_GETNSRCP(frwl) < 2) { dprintf(("%s src range set but n_src_p=%d\n", err_prefix, IP_FW_GETNSRCP(frwl))); return (EINVAL); } if ((frwl->fw_flg & IP_FW_F_DRNG) && IP_FW_GETNDSTP(frwl) < 2) { dprintf(("%s dst range set but n_dst_p=%d\n", err_prefix, IP_FW_GETNDSTP(frwl))); return (EINVAL); } if (IP_FW_GETNSRCP(frwl) + IP_FW_GETNDSTP(frwl) > IP_FW_MAX_PORTS) { dprintf(("%s too many ports (%d+%d)\n", err_prefix, IP_FW_GETNSRCP(frwl), IP_FW_GETNDSTP(frwl))); return (EINVAL); } /* * Protocols other than TCP/UDP don't use port range */ if ((frwl->fw_prot != IPPROTO_TCP) && (frwl->fw_prot != IPPROTO_UDP) && (IP_FW_GETNSRCP(frwl) || IP_FW_GETNDSTP(frwl))) { dprintf(("%s port(s) specified for non TCP/UDP rule\n", err_prefix)); return (EINVAL); } /* * Rather than modify the entry to make such entries work, * we reject this rule and require user level utilities * to enforce whatever policy they deem appropriate. */ if ((frwl->fw_src.s_addr & (~frwl->fw_smsk.s_addr)) || (frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) { dprintf(("%s rule never matches\n", err_prefix)); return (EINVAL); } if ((frwl->fw_flg & IP_FW_F_FRAG) && (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) { if (frwl->fw_nports) { dprintf(("%s cannot mix 'frag' and ports\n", err_prefix)); return (EINVAL); } if (frwl->fw_prot == IPPROTO_TCP && frwl->fw_tcpf != frwl->fw_tcpnf) { dprintf(("%s cannot mix 'frag' and TCP flags\n", err_prefix)); return (EINVAL); } } /* Check command specific stuff */ switch (frwl->fw_flg & IP_FW_F_COMMAND) { case IP_FW_F_REJECT: if (frwl->fw_reject_code >= 0x100 && !(frwl->fw_prot == IPPROTO_TCP && frwl->fw_reject_code == IP_FW_REJECT_RST)) { dprintf(("%s unknown reject code\n", err_prefix)); return (EINVAL); } break; case IP_FW_F_DIVERT: /* Diverting to port zero is invalid */ case IP_FW_F_PIPE: /* piping through 0 is invalid */ case IP_FW_F_TEE: if (frwl->fw_divert_port == 0) { dprintf(("%s can't divert to port 0\n", err_prefix)); return (EINVAL); } break; case IP_FW_F_DENY: case IP_FW_F_ACCEPT: case IP_FW_F_COUNT: case IP_FW_F_SKIPTO:#ifdef IPFIREWALL_FORWARD case IP_FW_F_FWD:#endif break; default: dprintf(("%s invalid command\n", err_prefix)); return (EINVAL); } return 0;}static intip_fw_ctl(struct sockopt *sopt){ int error, s; size_t size; char *buf, *bp; struct ip_fw_chain *fcp; struct ip_fw frwl; /* Disallow sets in really-really secure mode. */ if (sopt->sopt_dir == SOPT_SET && securelevel >= 3) return (EPERM); error = 0; switch (sopt->sopt_name) { case IP_FW_GET: for (fcp = LIST_FIRST(&ip_fw_chain), size = 0; fcp; fcp = LIST_NEXT(fcp, chain)) size += sizeof *fcp->rule; buf = malloc(size, M_TEMP, M_WAITOK); if (buf == 0) { error = ENOBUFS; break; } for (fcp = LIST_FIRST(&ip_fw_chain), bp = buf; fcp; fcp = LIST_NEXT(fcp, chain)) { bcopy(fcp->rule, bp, sizeof *fcp->rule); bp += sizeof *fcp->rule; } error = sooptcopyout(sopt, buf, size); FREE(buf, M_TEMP); break; case IP_FW_FLUSH: for (fcp = ip_fw_chain.lh_first; fcp != 0 && fcp->rule->fw_number != IPFW_DEFAULT_RULE; fcp = ip_fw_chain.lh_first) { s = splnet(); LIST_REMOVE(fcp, chain); FREE(fcp->rule, M_IPFW); FREE(fcp, M_IPFW); splx(s); } break; case IP_FW_ZERO: if (sopt->sopt_val != 0) { error = sooptcopyin(sopt, &frwl, sizeof frwl, sizeof frwl); if (error || (error = zero_entry(&frwl))) break; } else { error = zero_entry(0); } break; case IP_FW_ADD: error = sooptcopyin(sopt, &frwl, sizeof frwl, sizeof frwl); if (error || (error = check_ipfw_struct(&frwl))) break; if (frwl.fw_number == IPFW_DEFAULT_RULE) { dprintf(("%s can't add rule %u\n", err_prefix, (unsigned)IPFW_DEFAULT_RULE)); error = EINVAL; } else { error = add_entry(&ip_fw_chain, &frwl); } break; case IP_FW_DEL: error = sooptcopyin(sopt, &frwl, sizeof frwl, sizeof frwl); if (error) break; if (frwl.fw_number == IPFW_DEFAULT_RULE) { dprintf(("%s can't delete rule %u\n", err_prefix, (unsigned)IPFW_DEFAULT_RULE)); error = EINVAL; } else { error = del_entry(&ip_fw_chain, frwl.fw_number); } break; default: printf("ip_fw_ctl invalid option %d\n", sopt->sopt_name); error = EINVAL ; } return (error);}struct ip_fw_chain *ip_fw_default_rule ;voidip_fw_init(void){ struct ip_fw default_rule; ip_fw_chk_ptr = ip_fw_chk; ip_fw_ctl_ptr = ip_fw_ctl; LIST_INIT(&ip_fw_chain); bzero(&default_rule, sizeof default_rule); default_rule.fw_prot = IPPROTO_IP; default_rule.fw_number = IPFW_DEFAULT_RULE;#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT default_rule.fw_flg |= IP_FW_F_ACCEPT;#else default_rule.fw_flg |= IP_FW_F_DENY;#endif default_rule.fw_flg |= IP_FW_F_IN | IP_FW_F_OUT; if (check_ipfw_struct(&default_rule) != 0 || add_entry(&ip_fw_chain, &default_rule)) panic("ip_fw_init"); ip_fw_default_rule = ip_fw_chain.lh_first ; printf("IP packet filtering initialized, "#ifdef IPDIVERT "divert enabled, ");#else "divert disabled, ");#endif#ifdef IPFIREWALL_FORWARD printf("rule-based forwarding enabled, ");#else printf("rule-based forwarding disabled, ");#endif#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT printf("default to accept, ");#endif#ifndef IPFIREWALL_VERBOSE printf("logging disabled\n");#else if (fw_verbose_limit == 0) printf("unlimited logging\n"); else printf("logging limited to %d packets/entry\n", fw_verbose_limit);#endif}static ip_fw_chk_t *old_chk_ptr;static ip_fw_ctl_t *old_ctl_ptr;#if defined(IPFIREWALL_MODULE) && !defined(KLD_MODULE)#include <sys/exec.h>#include <sys/sysent.h>#include <sys/lkm.h>MOD_MISC(ipfw);static intipfw_load(struct lkm_table *lkmtp, int cmd){ int s=splnet(); old_chk_ptr = ip_fw_chk_ptr; old_ctl_ptr = ip_fw_ctl_ptr; ip_fw_init(); splx(s); return 0;}static intipfw_unload(struct lkm_table *lkmtp, int cmd){ int s=splnet(); ip_fw_chk_ptr = old_chk_ptr; ip_fw_ctl_ptr = old_ctl_ptr; while (LIST_FIRST(&ip_fw_chain) != NULL) { struct ip_fw_chain *fcp = LIST_FIRST(&ip_fw_chain); LIST_REMOVE(LIST_FIRST(&ip_fw_chain), chain); free(fcp->rule, M_IPFW); free(fcp, M_IPFW); } splx(s); printf("IP firewall unloaded\n"); return 0;}intipfw_mod(struct lkm_table *lkmtp, int cmd, int ver){ MOD_DISPATCH(ipfw, lkmtp, cmd, ver, ipfw_load, ipfw_unload, lkm_nullcmd);}#elsestatic intipfw_modevent(module_t mod, int type, void *unused){ int s; switch (type) { case MOD_LOAD: s = splnet(); old_chk_ptr = ip_fw_chk_ptr; old_ctl_ptr = ip_fw_ctl_ptr; ip_fw_init(); splx(s); return 0; case MOD_UNLOAD: s = splnet(); ip_fw_chk_ptr = old_chk_ptr; ip_fw_ctl_ptr = old_ctl_ptr; while (LIST_FIRST(&ip_fw_chain) != NULL) { struct ip_fw_chain *fcp = LIST_FIRST(&ip_fw_chain); LIST_REMOVE(LIST_FIRST(&ip_fw_chain), chain); free(fcp->rule, M_IPFW); free(fcp, M_IPFW); } splx(s); printf("IP firewall unloaded\n"); return 0; default: break; } return 0;}static moduledata_t ipfwmod = { "ipfw", ipfw_modevent, 0};#ifndef OSKITDECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PSEUDO, SI_ORDER_ANY);#elsevoidoskit_freebsd_net_ipfw_init() /* XXX: HACK HACK HACK */{ ipfw_modevent(NULL, MOD_LOAD, NULL);}#endif /* #ifndef OSKIT */#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -