📄 ip_fw.c
字号:
/* * Copyright (c) 1993 Daniel Boulet * Copyright (c) 1994 Ugen J.S.Antsilevich * * Redistribution and use in source forms, with and without modification, * are permitted provided that this entire comment appears intact. * * Redistribution in binary form may occur without any restrictions. * Obviously, it would be nice if you gave credit where credit is due * but requiring it would be too onerous. * * This software is provided ``AS IS'' without any warranties of any kind. * *//* * Implement IP packet firewall */#include <sys/param.h>#include <sys/systm.h>#include <sys/malloc.h>#include <sys/mbuf.h>#include <sys/queue.h>#include <sys/kernel.h>#if 0 /* XXX -current, but not -stable */#include <sys/sysctl.h>#endif#include <net/if.h>#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#include <netinet/tcp.h>#include <netinet/udp.h>#include <netinet/ip_icmp.h>#include <netinet/ip_fw.h>static int fw_debug = 1;#ifdef IPFIREWALL_VERBOSEstatic int fw_verbose = 1;#elsestatic int fw_verbose = 0;#endif#ifdef IPFIREWALL_VERBOSE_LIMITstatic int fw_verbose_limit = IPFIREWALL_VERBOSE_LIMIT;#elsestatic int fw_verbose_limit = 0;#endifLIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain;#ifdef SYSCTL_NODESYSCTL_NODE(net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");SYSCTL_INT(net_inet_ip_fw, OID_AUTO, debug, CTLFLAG_RW, &fw_debug, 0, "");SYSCTL_INT(net_inet_ip_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw_verbose, 0, "");SYSCTL_INT(net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw_verbose_limit, 0, "");#endif#define dprintf(a) if (!fw_debug); else printf a#define print_ip(a) printf("%ld.%ld.%ld.%ld",(ntohl(a.s_addr)>>24)&0xFF,\ (ntohl(a.s_addr)>>16)&0xFF,\ (ntohl(a.s_addr)>>8)&0xFF,\ (ntohl(a.s_addr))&0xFF);#define dprint_ip(a) if (!fw_debug); else print_ip(a)static int add_entry __P((struct ip_fw_head *chainptr, struct ip_fw *frwl));static int del_entry __P((struct ip_fw_head *chainptr, struct ip_fw *frwl));static int zero_entry __P((struct mbuf *m));static struct ip_fw * check_ipfw_struct __P(( struct mbuf *m));static int ipopts_match __P((struct ip *ip, struct ip_fw *f));static int port_match __P((u_short *portptr, int nports, u_short port, int range_flag));static int tcpflg_match __P((struct tcphdr *tcp, struct ip_fw *f));static void ipfw_report __P((char *txt, int rule, struct ip *ip, int counter));/* * Returns 1 if the port is matched by the vector, 0 otherwise */static inline int port_match(portptr, nports, port, range_flag) u_short *portptr; int nports; u_short port; int range_flag;{ if (!nports) return 1; if (range_flag) { if (portptr[0] <= port && port <= portptr[1]) { return 1; } nports -= 2; portptr += 2; } while (nports-- > 0) { if (*portptr++ == port) { return 1; } } return 0;}static inttcpflg_match(tcp, f) struct tcphdr *tcp; struct ip_fw *f;{ u_char flg_set, flg_clr; if ((f->fw_tcpf & IP_FW_TCPF_ESTAB) && (tcp->th_flags & (IP_FW_TCPF_RST | IP_FW_TCPF_ACK))) return 1; flg_set = tcp->th_flags & f->fw_tcpf; flg_clr = tcp->th_flags & f->fw_tcpnf; if (flg_set != f->fw_tcpf) return 0; if (flg_clr) return 0; return 1;}static inticmptype_match(struct icmp *icmp, struct ip_fw *f){ int type; if (!(f->fw_flg & IP_FW_F_ICMPBIT)) return(1); type = icmp->icmp_type; /* check for matching type in the bitmap */ if (f->fw_icmptypes[type / (sizeof(unsigned) * 8)] & (1U << (type % (8 * sizeof(unsigned))))) return(1); return(0); /* no match */}static intipopts_match(ip, f) struct ip *ip; struct ip_fw *f;{ register u_char *cp; int opt, optlen, cnt; u_char opts, nopts, nopts_sve; cp = (u_char *)(ip + 1); cnt = (ip->ip_hl << 2) - sizeof (struct ip); opts = f->fw_ipopt; nopts = nopts_sve = f->fw_ipnopt; for (; cnt > 0; cnt -= optlen, cp += optlen) { opt = cp[IPOPT_OPTVAL]; if (opt == IPOPT_EOL) break; if (opt == IPOPT_NOP) optlen = 1; else { optlen = cp[IPOPT_OLEN]; if (optlen <= 0 || optlen > cnt) { return 0; /*XXX*/ } } switch (opt) { default: break; case IPOPT_LSRR: opts &= ~IP_FW_IPOPT_LSRR; nopts &= ~IP_FW_IPOPT_LSRR; break; case IPOPT_SSRR: opts &= ~IP_FW_IPOPT_SSRR; nopts &= ~IP_FW_IPOPT_SSRR; break; case IPOPT_RR: opts &= ~IP_FW_IPOPT_RR; nopts &= ~IP_FW_IPOPT_RR; break; case IPOPT_TS: opts &= ~IP_FW_IPOPT_TS; nopts &= ~IP_FW_IPOPT_TS; break; } if (opts == nopts) break; } if (opts == 0 && nopts == nopts_sve) return 1; else return 0;}static voidipfw_report(char *txt, int rule, struct ip *ip, int counter){ struct tcphdr *tcp = (struct tcphdr *) ((u_long *) ip + ip->ip_hl); struct udphdr *udp = (struct udphdr *) ((u_long *) ip + ip->ip_hl); struct icmp *icmp = (struct icmp *) ((u_long *) ip + ip->ip_hl); if (!fw_verbose) return; if (fw_verbose_limit != 0 && counter > fw_verbose_limit) return; printf("ipfw: %d %s ",rule, txt); switch (ip->ip_p) { case IPPROTO_TCP: printf("TCP "); print_ip(ip->ip_src); printf(":%d ", ntohs(tcp->th_sport)); print_ip(ip->ip_dst); printf(":%d", ntohs(tcp->th_dport)); break; case IPPROTO_UDP: printf("UDP "); print_ip(ip->ip_src); printf(":%d ", ntohs(udp->uh_sport)); print_ip(ip->ip_dst); printf(":%d", ntohs(udp->uh_dport)); break; case IPPROTO_ICMP: printf("ICMP:%u.%u ", icmp->icmp_type, icmp->icmp_code); print_ip(ip->ip_src); printf(" "); print_ip(ip->ip_dst); break; default: printf("P:%d ", ip->ip_p); print_ip(ip->ip_src); printf(" "); print_ip(ip->ip_dst); break; } if ((ip->ip_off & IP_OFFMASK)) printf(" Fragment = %d",ip->ip_off & IP_OFFMASK); printf("\n");}/* * Returns 1 if it should be accepted, 0 otherwise. */int ip_fw_chk(m, ip, rif, dir) struct mbuf *m; struct ip *ip; struct ifnet *rif; int dir;{ struct ip_fw_chain *chain; register struct ip_fw *f = NULL; struct tcphdr *tcp = (struct tcphdr *) ((u_long *) ip + ip->ip_hl); struct udphdr *udp = (struct udphdr *) ((u_long *) ip + ip->ip_hl); struct icmp *icmp = (struct icmp *) ((u_long *) ip + ip->ip_hl); struct ifaddr *ia = NULL, *ia_p; struct in_addr src, dst, ia_i; u_short src_port = 0, dst_port = 0; u_short f_prt = 0, prt, len = 0; /* * ... else if non-zero, highly unusual and interesting, but * we're not going to pass it... */ if ((ip->ip_off & IP_OFFMASK) == 1) { static int frag_counter = 0; ++frag_counter; ipfw_report("Refuse", -1, ip, frag_counter); m_freem(m); return 0; } src = ip->ip_src; dst = ip->ip_dst; /* * If we got interface from which packet came-store pointer to it's * first adress */ if (rif != NULL) ia = rif->if_addrlist; /* * Determine the protocol and extract some useful stuff */ switch (ip->ip_p) { case IPPROTO_TCP: src_port = ntohs(tcp->th_sport); dst_port = ntohs(tcp->th_dport); prt = IP_FW_F_TCP; len = sizeof (*tcp); break; case IPPROTO_UDP: src_port = ntohs(udp->uh_sport); dst_port = ntohs(udp->uh_dport); prt = IP_FW_F_UDP; len = sizeof (*udp); break; case IPPROTO_ICMP: prt = IP_FW_F_ICMP; len = sizeof (*icmp); break; default: prt = IP_FW_F_ALL; break; } /* XXX Check that we have sufficient header for TCP analysis */ /* * Go down the chain, looking for enlightment */ for (chain=ip_fw_chain.lh_first; chain; chain = chain->chain.le_next) { f = chain->rule; /* Check direction inbound */ if (!dir && !(f->fw_flg & IP_FW_F_IN)) continue; /* Check direction outbound */ if (dir && !(f->fw_flg & IP_FW_F_OUT)) continue; /* Fragments */ if ((f->fw_flg & IP_FW_F_FRAG) && !(ip->ip_off & IP_OFFMASK)) continue; /* If src-addr doesn't match, not this rule. */ if ((src.s_addr & f->fw_smsk.s_addr) != f->fw_src.s_addr) continue; /* If dest-addr doesn't match, not this rule. */ if ((dst.s_addr & f->fw_dmsk.s_addr) != f->fw_dst.s_addr) continue; /* If a i/f name was specified, and we don't know */ if ((f->fw_flg & IP_FW_F_IFNAME) && !rif) continue; /* If a i/f name was specified, check it */ if ((f->fw_flg & IP_FW_F_IFNAME) && f->fw_via_name[0]) { /* Not same unit, don't match */ if (!(f->fw_flg & IP_FW_F_IFUWILD) && rif->if_unit != f->fw_via_unit) continue; /* Not same name */ if (strncmp(rif->if_name, f->fw_via_name, FW_IFNLEN)) continue; } /* If a i/f addr was specified, check it */ if (!(f->fw_flg & IP_FW_F_IFNAME) && f->fw_via_ip.s_addr) { int match = 0; for (ia_p = ia; ia_p != NULL; ia_p = ia_p->ifa_next) { if ((ia_p->ifa_addr == NULL)) continue; if (ia_p->ifa_addr->sa_family != AF_INET) continue; ia_i.s_addr = ((struct sockaddr_in *) (ia_p->ifa_addr))->sin_addr.s_addr; if (ia_i.s_addr != f->fw_via_ip.s_addr) continue; match = 1; break; } if (!match) continue; } /* * Check IP options */ if (f->fw_ipopt != f->fw_ipnopt) if (!ipopts_match(ip, f)) continue; /* * Check protocol */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -