📄 firewall.c
字号:
/* $Header: /usr/cvsroot/target/src/wrn/wm/demo/lib/firewall.c,v 1.4 2003/01/15 14:04:31 josh Exp $ *//* * Copyright (C) 1999-2005 Wind River Systems, Inc. * All rights reserved. Provided under license only. * Distribution or other use of this software is only * permitted pursuant to the terms of a license agreement * from Wind River Systems (and is otherwise prohibited). * Refer to that license agreement for terms of use. *//**************************************************************************** * Copyright 1998 Integrated Systems, Inc. * All rights reserved. ****************************************************************************//* * Rudimentary firewall built on top of Attache. * This is a work in progress, I need the basic functionality to solve * a short term problem but the code will need more work to make * it as general as it should be. *//* * $Log: firewall.c,v $ * Revision 1.4 2003/01/15 14:04:31 josh * directory structure shifting * * Revision 1.3 2001/11/08 15:56:21 tneale * Updated for newest file layout * * Revision 1.2 2001/11/06 20:11:11 josh * updating include paths to include proper path to layout directory * * Revision 1.1.1.1 2001/11/05 17:48:41 tneale * Tornado shuffle * * Revision 2.4 2001/01/19 22:23:41 paul * Update copyright. * * Revision 2.3 2000/03/17 00:12:38 meister * Update copyright message * * Revision 2.2 1998/09/08 05:21:46 sra * Compiler warnings. * * Revision 2.1 1998/09/06 08:11:08 sra * Packet filtering hooks in Attache, rudimentary firewall * implementation in Snark. * *//* [clearcase]modification history-------------------01a,19apr05,job update copyright notices*/#include <wrn/wm/common/config.h>#include <wrn/wm/common/glue.h>#include <wrn/wm/attache/config.h>#include <wrn/wm/attache/timer.h>#include <wrn/wm/attache/packet.h>#include <wrn/wm/attache/net.h>#include <wrn/wm/attache/route.h>#include <wrn/wm/attache/ip.h>#include <wrn/wm/attache/udp.h>#include <wrn/wm/attache/glue.h>#include <wrn/wm/util/layout/ip.h>#if INSTALL_ATTACHE_IPV6#include <wrn/wm/util/layout/ip6.h>#endif#include <wrn/wm/demo/snarklib.h>#include <wrn/wm/demo/read_ini.h>#include <wrn/wm/demo/parse.h>enum fw_action { FW_ALLOW = 0, FW_DROP = 1, FW_RESET = 2};struct filter { struct filter *next; enum fw_action action; bits8_t proto, src_prefix, dst_prefix; bits16_t src_low_port, src_high_port, dst_low_port, dst_high_port; ipaddr_t src_addr, dst_addr; char ifname[20]; unsigned negate_proto : 1; unsigned negate_src_addr : 1; unsigned negate_dst_addr : 1; unsigned negate_src_port : 1; unsigned negate_dst_port : 1; unsigned negate_ifname : 1; unsigned tcp_established : 1; unsigned tcp_setup : 1;};enum filter_argv { ARGV_ACTION, ARGV_PROTO, ARGV_SRC_ADDR, ARGV_SRC_PORT, ARGV_DST_ADDR, ARGV_DST_PORT, ARGV_IFNAME, ARGV_MINLENGTH};enum fw_tcpflag { TCPFLAG_ESTABLISHED, TCPFLAG_SETUP,};static struct action_table { char *name; enum fw_action action;} action_table[] = { { "allow", FW_ALLOW }, { "drop", FW_DROP }, { "reset", FW_RESET },};static struct tcpflag_table { char *name; enum fw_tcpflag flag;} tcpflag_table[] = { { "established", TCPFLAG_ESTABLISHED }, { "setup", TCPFLAG_SETUP },};static struct proto_table { char *name; bits8_t proto;} proto_table[] = { { "*", 0 }, { "icmp", IP_PROTOCOL_is_ICMP }, { "tcp", IP_PROTOCOL_is_TCP }, { "udp", IP_PROTOCOL_is_UDP },};static struct filter *ifilter = 0;static struct filter *ofilter = 0;static struct filter *ffilter = 0;static struct keyword_table action_keywords, proto_keywords, tcpflag_keywords;#ifndef GET_TCP_HEADER_DESTINATION_PORT#define GET_TCP_HEADER_DESTINATION_PORT(_P_) \ GET_IP_PORT_NUMBER(PTR_TCP_HEADER_DESTINATION_PORT(_P_))#endif#ifndef GET_TCP_HEADER_SOURCE_PORT#define GET_TCP_HEADER_SOURCE_PORT(_P_) \ GET_IP_PORT_NUMBER(PTR_TCP_HEADER_SOURCE_PORT(_P_))#endif/* * Compare the first len bits of two ipaddr_ts, return nonzero if they match. */static int ipaddr_match (ipaddr_t *a1, ipaddr_t *a2, bits8_t len){ ipaddr_bits_t *b1, *b2; BUG_ASSERT(a1 && a2 && len <= MAX_IP_ADDR_LEN * 8); if (!len) return 1; if (GET_IPADDR_TYPE(a1) != GET_IPADDR_TYPE(a2)) return 0; for (b1 = PTR_IPADDR_BITS(a1), b2 = PTR_IPADDR_BITS(a2); len >= 8; b1++, b2++, len -= 8) if (*b1 != *b2) return 0; return !((*b1 ^ *b2) >> (8 - len));}#define FILTER_ALLOW() \ do { \ BUG_SUPPORT(ipaddr_to_string(&src_addr, src_host, sizeof(src_host))); \ BUG_SUPPORT(ipaddr_to_string(&dst_addr, dst_host, sizeof(dst_host))); \ BUG(BUG_SNARK_FIREWALL_ALLOW_PKT, BUG_CONTINUABLE, p, \ (BUG_OUT, "FW: Allow: %u %s %u %s %u %s", \ proto, src_host, src_port, dst_host, dst_port, ifname)); \ return (int) FW_ALLOW; \ } while (0)#define FILTER_DROP() \ do { \ BUG_SUPPORT(ipaddr_to_string(&src_addr, src_host, sizeof(src_host))); \ BUG_SUPPORT(ipaddr_to_string(&dst_addr, dst_host, sizeof(dst_host))); \ BUG(BUG_SNARK_FIREWALL_DROP_PKT, BUG_CONTINUABLE, p, \ (BUG_OUT, "FW: Drop: %u %s %u %s %u %s", \ proto, src_host, src_port, dst_host, dst_port, ifname)); \ return (int) FW_DROP; \ } while (0)#define FILTER_RESET() \ do { \ BUG_SUPPORT(ipaddr_to_string(&src_addr, src_host, sizeof(src_host))); \ BUG_SUPPORT(ipaddr_to_string(&dst_addr, dst_host, sizeof(dst_host))); \ BUG(BUG_SNARK_FIREWALL_RESET_PKT, BUG_CONTINUABLE, p, \ (BUG_OUT, "FW: Reset: %u %s %u %s %u %s", \ proto, src_host, src_port, dst_host, dst_port, ifname)); \ return (int) FW_RESET; \ } while (0)static int filter(packet *p, struct filter *f, bits8_t *ip_hdr){ bits8_t proto = 0; bits16_t src_port = 0, dst_port = 0; ipaddr_t src_addr, dst_addr; char *ifname = ""; bits8_t *tp_hdr = 0; int tcp_established = 0, tcp_setup = 0; size_t optlen; BUG_SUPPORT(char src_host[MAX_IPADDR_STRING_LEN]); BUG_SUPPORT(char dst_host[MAX_IPADDR_STRING_LEN]); BUG_ASSERT(p && ip_hdr); /* * Extract relevant fields from the packet. */ switch (GET_IP_HEADER_VERSION(ip_hdr)) {#if INSTALL_ATTACHE_IPV4 case IP_HEADER_VERSION_is_IPV4: optlen = GET_IP_HEADER_HEADER_LENGTH(ip_hdr) * 4 - SIZEOF_IP_HEADER; tp_hdr = ip_hdr + SIZEOF_IP_HEADER + optlen; break;#endif /* INSTALL_ATTACHE_IPV4 */#if INSTALL_ATTACHE_IPV6 case IP_HEADER_VERSION_is_IPV6: /* This isn't right. */ optlen = 0; tp_hdr = ip_hdr + SIZEOF_IP6_HEADER + optlen; break;#endif /* INSTALL_ATTACHE_IPV6 */ default: FILTER_DROP(); } /* For the moment, just drop any packets containing IP options. */ if (optlen) FILTER_DROP(); proto = GET_IP_HEADER_PROTOCOL(ip_hdr); GET_IP_SRC_ADDR(ip_hdr, &src_addr); GET_IP_DST_ADDR(ip_hdr, &dst_addr); switch (proto) { case IP_PROTOCOL_is_TCP: if (p->pkt_data + p->pkt_datalen < tp_hdr + SIZEOF_TCP_HEADER) FILTER_DROP(); src_port = GET_TCP_HEADER_SOURCE_PORT(tp_hdr); dst_port = GET_TCP_HEADER_DESTINATION_PORT(tp_hdr); tcp_established = GET_TCP_HEADER_ACK(tp_hdr) || GET_TCP_HEADER_RST(tp_hdr); tcp_setup = GET_TCP_HEADER_SYN(tp_hdr) && !GET_TCP_HEADER_ACK(tp_hdr); break; case IP_PROTOCOL_is_UDP: if (p->pkt_data + p->pkt_datalen < tp_hdr + SIZEOF_UDP_HEADER) FILTER_DROP(); src_port = GET_UDP_HEADER_SOURCE_PORT(tp_hdr); dst_port = GET_UDP_HEADER_DESTINATION_PORT(tp_hdr); break; default: src_port = dst_port = 0; } ifname = (p->pkt_n && p->pkt_n->s_name) ? p->pkt_n->s_name : ""; /* * Look for a matching rule. */ while (f && ((f->proto && (f->negate_proto ^ (proto != f->proto))) || (proto == IP_PROTOCOL_is_TCP && ((f->tcp_setup && !tcp_setup) || (f->tcp_established && !tcp_established))) || (f->negate_src_port ^ (src_port < f->src_low_port || src_port > f->src_high_port)) || (f->negate_dst_port ^ (dst_port < f->dst_low_port || dst_port > f->dst_high_port)) || (f->negate_src_addr ^ !ipaddr_match(&src_addr, &f->src_addr, f->src_prefix)) || (f->negate_dst_addr ^ !ipaddr_match(&dst_addr, &f->dst_addr, f->dst_prefix)) || (*f->ifname && (f->negate_ifname ^ (STRCMP(ifname, f->ifname) != 0))))) f = f->next; /* * If we found a rule, apply it. */ if (f) { switch (f->action) { case FW_ALLOW: FILTER_ALLOW(); case FW_RESET:#if 0 /* * p->pkt_data would need adjustment here */ tcp_clrs(p);#endif FILTER_RESET(); case FW_DROP: FILTER_DROP(); } } /* * For now, if we didn't find a matching rule, silently drop the packet. */ FILTER_DROP();}int snark_firewall_inbound_filter(packet *p){ return filter(p, ifilter, PKT_GET_IP_HEADER(p));}int snark_firewall_outbound_filter(packet *p){ return filter(p, ofilter, p->pkt_data);}int snark_firewall_forward_filter(packet *p){ return filter(p, ffilter, p->pkt_data);} static int parse_action(struct filter *rule, char **av){ struct action_table *entry; if (!(entry = keyword_find(&action_keywords, av[ARGV_ACTION]))) return 0; rule->action = entry->action; return 1;}static int parse_proto(struct filter *rule, char **av){ struct proto_table *entry; char *sep; if (*av[ARGV_PROTO] == '!') { rule->negate_proto = 1; av[ARGV_PROTO]++; } if ((entry = keyword_find(&proto_keywords, av[ARGV_PROTO])) != 0) { rule->proto = entry->proto; return 1; } rule->proto = STRTOUL(av[ARGV_PROTO], &sep, 10); return av[ARGV_PROTO] != '\0' && *sep == '\0';}static int parse_ipaddr(struct filter *rule, char **av, int ai){ ipaddr_t *addr; bits8_t *prefix; unsigned negate = 0; char *pfx; if (*av[ai] == '!') { negate = 1; av[ai]++; } switch (ai) { case ARGV_SRC_ADDR: rule->negate_src_addr = negate; addr = &rule->src_addr; prefix = &rule->src_prefix; break; case ARGV_DST_ADDR: rule->negate_dst_addr = negate; addr = &rule->dst_addr; prefix = &rule->dst_prefix; break; default: return 0; } if (av[ai][0] == '*' && av[ai][1] == '\0') { *prefix = 0; SET_IPADDR_TYPE(addr, IPNONE); return 1; } for (pfx = av[ai]; *pfx != '\0'; ++pfx) { if (*pfx == '/') { *pfx++ = '\0'; if (*pfx == '\0') return 0; break; } } string_to_ipaddr(av[ai], addr); if (GET_IPADDR_TYPE(addr) == IPNONE) return 0; if (*pfx == '\0') { *prefix = IPADDR_LENGTH(addr) * 8; return 1; } else { *prefix = STRTOUL(pfx, &pfx, 10); return *pfx == '\0' && *prefix <= IPADDR_LENGTH(addr) * 8; }}static int parse_port(struct filter *rule, char **av, int ai){ bits16_t *lowport, *highport; unsigned negate = 0; char *sep; if (*av[ai] == '!') { negate = 1; av[ai]++; } switch (ai) { case ARGV_SRC_PORT: rule->negate_src_port = negate; lowport = &rule->src_low_port; highport = &rule->src_high_port; break; case ARGV_DST_PORT: rule->negate_dst_port = negate; lowport = &rule->dst_low_port; highport = &rule->dst_high_port; break; default: return 0; } switch (av[ai][0]) { case '\0': return 0; case '*': if (av[ai][1] != '\0') return 0; *lowport = 0; *highport = 0xFFFF; return 1; } *lowport = STRTOUL(av[ai], &sep, 10); switch (*sep) { case '\0': *highport = *lowport; return 1; case '-': if (*++sep == '\0') return 0; *highport = STRTOUL(sep, &sep, 10); return *sep == '\0'; default: return 0; }}static int parse_ifname(struct filter *rule, char **av){ if (*av[ARGV_IFNAME] == '!') { rule->negate_ifname = 1; av[ARGV_IFNAME]++; } if (*av[ARGV_IFNAME] == '*' && *++av[ARGV_IFNAME] != '\0') return 0; strncpy(rule->ifname, av[ARGV_IFNAME], sizeof(rule->ifname) - 1); return 1;}static int parse_tcpflag(struct filter *rule, char **av, int ac){ struct tcpflag_table *entry; if (rule->proto != IP_PROTOCOL_is_TCP || ac == ARGV_MINLENGTH) return 1; if (ac > ARGV_MINLENGTH + 1 || (entry = keyword_find(&tcpflag_keywords, av[ARGV_MINLENGTH])) == 0) return 0; switch (entry->flag) { case TCPFLAG_ESTABLISHED: rule->tcp_established = 1; return 1; case TCPFLAG_SETUP: rule->tcp_setup = 1; return 1; default: return 0; }}static void config_1 (struct ini_handle *ini_handle, char *name, struct filter **tail){ static char snark_section[] = "etc snark firewall"; struct filter *rule = 0; char *s, buf[256], *av[20]; int ac; BUG_ASSERT(sizeof(buf) >= ini_handle->buflen); *tail = 0; for (s = ini_iter_start(ini_handle, snark_section, name); s; s = ini_iter_next(ini_handle)) { if (!rule && !(rule = GLUE_ALLOC(sizeof(*rule)))) { BUG(BUG_SNARK_FIREWALL_CONFIG_ALLOC_FAILED, BUG_FATAL, s, (BUG_OUT, "fw_config_1(): allocation failed for rule: %s", s)); return; } MEMSET(rule, 0, sizeof(*rule)); STRCPY(buf, s); if ((ac = parse_line(buf, av, sizeof(av)/sizeof(*av))) < ARGV_MINLENGTH || !parse_action(rule, av) || !parse_proto(rule, av) || !parse_ipaddr(rule, av, ARGV_SRC_ADDR) || !parse_ipaddr(rule, av, ARGV_DST_ADDR) || !parse_port(rule, av, ARGV_SRC_PORT) || !parse_port(rule, av, ARGV_DST_PORT) || !parse_ifname(rule, av) || !parse_tcpflag(rule, av, ac)) { BUG(BUG_SNARK_FIREWALL_CONFIG_PARSE_ERROR, BUG_FATAL, s, (BUG_OUT, "fw_config_1(): couldn't parse rule: %s", s)); GLUE_FREE(rule); return; } *tail = rule; tail = &rule->next; rule = 0; }}void snark_firewall_init (void){ struct ini_handle *ini_handle = ini_open(256); KEYWORD_INIT(&action_keywords, action_table); KEYWORD_INIT(&proto_keywords, proto_table); KEYWORD_INIT(&tcpflag_keywords, tcpflag_table); config_1(ini_handle, "inbound-filter", &ifilter); config_1(ini_handle, "outbound-filter", &ofilter); config_1(ini_handle, "forward-filter", &ffilter); ini_close(ini_handle);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -