📄 ip_fw.c
字号:
if (f->fw_divert_port == ignport) continue; /* ignore this rule */ break; } /* Update statistics */ f->fw_pcnt += 1; f->fw_bcnt += ip->ip_len; f->timestamp = rtems_bsdnet_seconds_since_boot(); /* Log to console if desired */ if ((f->fw_flg & IP_FW_F_PRN) && fw_verbose) ipfw_report(f, ip, rif, oif); /* Take appropriate action */ switch (f->fw_flg & IP_FW_F_COMMAND) { case IP_FW_F_ACCEPT: return(0); case IP_FW_F_COUNT: continue; case IP_FW_F_DIVERT: return(f->fw_divert_port); case IP_FW_F_TEE: /* * XXX someday tee packet here, but beware that you * can't use m_copym() or m_copypacket() because * the divert input routine modifies the mbuf * (and these routines only increment reference * counts in the case of mbuf clusters), so need * to write custom routine. */ continue; case IP_FW_F_SKIPTO:#ifdef DIAGNOSTIC while (chain->chain.le_next && chain->chain.le_next->rule->fw_number < f->fw_skipto_rule)#else while (chain->chain.le_next->rule->fw_number < f->fw_skipto_rule)#endif chain = chain->chain.le_next; continue; } /* Deny/reject this packet using this rule */ rule = f; break; }#ifdef DIAGNOSTIC /* Rule 65535 should always be there and should always match */ if (!chain) panic("ip_fw: chain");#endif /* * At this point, we're going to drop the packet. * Send a reject notice if all of the following are true: * * - The packet matched a reject rule * - The packet is not an ICMP packet * - The packet is not a multicast or broadcast packet */ if ((rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT && ip->ip_p != IPPROTO_ICMP && !((*m)->m_flags & (M_BCAST|M_MCAST)) && !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { switch (rule->fw_reject_code) { case IP_FW_REJECT_RST: { struct tcphdr *const tcp = (struct tcphdr *) ((u_long *)ip + ip->ip_hl); struct tcpiphdr ti, *const tip = (struct tcpiphdr *) ip; if (offset != 0 || (tcp->th_flags & TH_RST)) break; ti.ti_i = *((struct ipovly *) ip); ti.ti_t = *tcp; bcopy(&ti, ip, sizeof(ti)); NTOHL(tip->ti_seq); NTOHL(tip->ti_ack); tip->ti_len = ip->ip_len - hlen - (tip->ti_off << 2); if (tcp->th_flags & TH_ACK) { tcp_respond(NULL, tip, *m, (tcp_seq)0, ntohl(tcp->th_ack), TH_RST); } else { if (tcp->th_flags & TH_SYN) tip->ti_len++; tcp_respond(NULL, tip, *m, tip->ti_seq + tip->ti_len, (tcp_seq)0, TH_RST|TH_ACK); } *m = NULL; break; } default: /* Send an ICMP unreachable using code */ icmp_error(*m, ICMP_UNREACH, rule->fw_reject_code, 0L, 0); *m = NULL; break; } }dropit: /* * Finally, drop the packet. */ if (*m) { m_freem(*m); *m = NULL; } return(0);}static intadd_entry(struct ip_fw_head *chainptr, struct ip_fw *frwl){ struct ip_fw *ftmp = 0; struct ip_fw_chain *fwc = 0, *fcp, *fcpl = 0; u_short nbr = 0; int s; fwc = malloc(sizeof *fwc, M_IPFW, M_DONTWAIT); ftmp = malloc(sizeof *ftmp, M_IPFW, M_DONTWAIT); if (!fwc || !ftmp) { dprintf(("%s malloc said no\n", err_prefix)); if (fwc) free(fwc, M_IPFW); if (ftmp) free(ftmp, M_IPFW); return (ENOSPC); } bcopy(frwl, ftmp, sizeof(struct ip_fw)); ftmp->fw_in_if.fu_via_if.name[FW_IFNLEN - 1] = '\0'; ftmp->fw_pcnt = 0L; ftmp->fw_bcnt = 0L; fwc->rule = ftmp; s = splnet(); if (!chainptr->lh_first) { LIST_INSERT_HEAD(chainptr, fwc, chain); splx(s); return(0); } else if (ftmp->fw_number == (u_short)-1) { if (fwc) free(fwc, M_IPFW); if (ftmp) free(ftmp, M_IPFW); splx(s); dprintf(("%s bad rule number\n", err_prefix)); return (EINVAL); } /* If entry number is 0, find highest numbered rule and add 100 */ if (ftmp->fw_number == 0) { for (fcp = chainptr->lh_first; fcp; fcp = fcp->chain.le_next) { if (fcp->rule->fw_number != (u_short)-1) nbr = fcp->rule->fw_number; else break; } if (nbr < (u_short)-1 - 100) nbr += 100; ftmp->fw_number = nbr; } /* Got a valid number; now insert it, keeping the list ordered */ for (fcp = chainptr->lh_first; fcp; fcp = fcp->chain.le_next) { if (fcp->rule->fw_number > ftmp->fw_number) { if (fcpl) { LIST_INSERT_AFTER(fcpl, fwc, chain); } else { LIST_INSERT_HEAD(chainptr, fwc, chain); } break; } else { fcpl = fcp; } } splx(s); return (0);}static intdel_entry(struct ip_fw_head *chainptr, u_short number){ struct ip_fw_chain *fcp; int s; s = splnet(); fcp = chainptr->lh_first; if (number != (u_short)-1) { for (; fcp; fcp = fcp->chain.le_next) { if (fcp->rule->fw_number == number) { LIST_REMOVE(fcp, chain); splx(s); free(fcp->rule, M_IPFW); free(fcp, M_IPFW); return 0; } } } splx(s); return (EINVAL);}static intzero_entry(struct mbuf *m){ struct ip_fw *frwl; struct ip_fw_chain *fcp; int s; if (m) { if (m->m_len != sizeof(struct ip_fw)) return(EINVAL); frwl = mtod(m, struct ip_fw *); } else frwl = NULL; /* * 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. */ s = splnet(); for (fcp = ip_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next) if (!frwl || frwl->fw_number == fcp->rule->fw_number) { fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0; fcp->rule->timestamp = 0; } splx(s); if (fw_verbose) { if (frwl) printf("ipfw: Entry %d cleared.\n", frwl->fw_number); else printf("ipfw: Accounting cleared.\n"); } return(0);}static struct ip_fw *check_ipfw_mbuf(struct mbuf *m){ /* Check length */ if (m->m_len != sizeof(struct ip_fw)) { dprintf(("%s len=%d, want %d\n", err_prefix, m->m_len, (int)sizeof(struct ip_fw))); return (NULL); } return(check_ipfw_struct(mtod(m, struct ip_fw *)));}static struct ip_fw *check_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 (NULL); } /* 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 (NULL); } /* 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 (NULL); } /* 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 (NULL); } /* 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 (NULL); } 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 (NULL); } 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 (NULL); } /* * 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(NULL); } /* * 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(NULL); } 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(NULL); } if (frwl->fw_prot == IPPROTO_TCP && frwl->fw_tcpf != frwl->fw_tcpnf) { dprintf(("%s cannot mix 'frag' with TCP flags\n", err_prefix)); return(NULL); } } /* 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(NULL); } break; case IP_FW_F_DIVERT: /* Diverting to port zero 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 (NULL); } break; case IP_FW_F_DENY: case IP_FW_F_ACCEPT: case IP_FW_F_COUNT: case IP_FW_F_SKIPTO: break; default: dprintf(("%s invalid command\n", err_prefix)); return(NULL); } return frwl;}static intip_fw_ctl(int stage, struct mbuf **mm){ int error; struct mbuf *m; if (stage == IP_FW_GET) { struct ip_fw_chain *fcp = ip_fw_chain.lh_first; *mm = m = m_get(M_WAIT, MT_SOOPTS); for (; fcp; fcp = fcp->chain.le_next) { memcpy(m->m_data, fcp->rule, sizeof *(fcp->rule)); m->m_len = sizeof *(fcp->rule); m->m_next = m_get(M_WAIT, MT_SOOPTS); m = m->m_next; m->m_len = 0; } return (0); } m = *mm; /* only allow get calls if secure mode > 2 */ if (securelevel > 2) { if (m) (void)m_free(m); return(EPERM); } if (stage == IP_FW_FLUSH) { while (ip_fw_chain.lh_first != NULL && ip_fw_chain.lh_first->rule->fw_number != (u_short)-1) { struct ip_fw_chain *fcp = ip_fw_chain.lh_first; int s = splnet(); LIST_REMOVE(ip_fw_chain.lh_first, chain); splx(s); free(fcp->rule, M_IPFW); free(fcp, M_IPFW); } if (m) (void)m_free(m); return (0); } if (stage == IP_FW_ZERO) { error = zero_entry(m); if (m) (void)m_free(m); return (error); } if (m == NULL) { printf("%s NULL mbuf ptr\n", err_prefix); return (EINVAL); } if (stage == IP_FW_ADD) { struct ip_fw *frwl = check_ipfw_mbuf(m); if (!frwl) error = EINVAL; else error = add_entry(&ip_fw_chain, frwl); if (m) (void)m_free(m); return error; } if (stage == IP_FW_DEL) { if (m->m_len != sizeof(struct ip_fw)) { dprintf(("%s len=%d, want %d\n", err_prefix, m->m_len, (int)sizeof(struct ip_fw))); error = EINVAL; } else if (mtod(m, struct ip_fw *)->fw_number == (u_short)-1) { dprintf(("%s can't delete rule 65535\n", err_prefix)); error = EINVAL; } else error = del_entry(&ip_fw_chain, mtod(m, struct ip_fw *)->fw_number); if (m) (void)m_free(m); return error; } dprintf(("%s unknown request %d\n", err_prefix, stage)); if (m) (void)m_free(m); return (EINVAL);}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 = (u_short)-1;#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) == NULL || add_entry(&ip_fw_chain, &default_rule)) panic(__FUNCTION__); printf("IP packet filtering initialized, "#ifdef IPDIVERT "divert enabled, ");#else "divert 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}#ifdef IPFIREWALL_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 (ip_fw_chain.lh_first != NULL) { struct ip_fw_chain *fcp = ip_fw_chain.lh_first; LIST_REMOVE(ip_fw_chain.lh_first, 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){ DISPATCH(lkmtp, cmd, ver, ipfw_load, ipfw_unload, lkm_nullcmd);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -