?? ipfwadm_core.c
字號:
/* Minor modifications to fit on compatibility framework: Rusty.Russell@rustcorp.com.au*/#include <linux/config.h>#define CONFIG_IP_FIREWALL#define CONFIG_IP_FIREWALL_VERBOSE#define CONFIG_IP_MASQUERADE#define CONFIG_IP_ACCT#define CONFIG_IP_TRANSPARENT_PROXY#if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE)#define CONFIG_IP_FIREWALL_NETLINK#endif/* * IP firewalling code. This is taken from 4.4BSD. Please note the * copyright message below. As per the GPL it must be maintained * and the licenses thus do not conflict. While this port is subject * to the GPL I also place my modifications under the original * license in recognition of the original copyright. * -- Alan Cox. * * $Id: ipfwadm_core.c,v 1.11 2002/01/24 15:50:31 davem Exp $ * * Ported from BSD to Linux, * Alan Cox 22/Nov/1994. * Zeroing /proc and other additions * Jos Vos 4/Feb/1995. * Merged and included the FreeBSD-Current changes at Ugen's request * (but hey it's a lot cleaner now). Ugen would prefer in some ways * we waited for his final product but since Linux 1.2.0 is about to * appear it's not practical - Read: It works, it's not clean but please * don't consider it to be his standard of finished work. * Alan Cox 12/Feb/1995 * Porting bidirectional entries from BSD, fixing accounting issues, * adding struct ip_fwpkt for checking packets with interface address * Jos Vos 5/Mar/1995. * Established connections (ACK check), ACK check on bidirectional rules, * ICMP type check. * Wilfred Mollenvanger 7/7/1995. * TCP attack protection. * Alan Cox 25/8/95, based on information from bugtraq. * ICMP type printk, IP_FW_F_APPEND * Bernd Eckenfels 1996-01-31 * Split blocking chain into input and output chains, add new "insert" and * "append" commands to replace semi-intelligent "add" command, let "delete". * only delete the first matching entry, use 0xFFFF (0xFF) as ports (ICMP * types) when counting packets being 2nd and further fragments. * Jos Vos <jos@xos.nl> 8/2/1996. * Add support for matching on device names. * Jos Vos <jos@xos.nl> 15/2/1996. * Transparent proxying support. * Willy Konynenberg <willy@xos.nl> 10/5/96. * Make separate accounting on incoming and outgoing packets possible. * Jos Vos <jos@xos.nl> 18/5/1996. * Added trap out of bad frames. * Alan Cox <alan@cymru.net> 17/11/1996 * * * Masquerading functionality * * Copyright (c) 1994 Pauline Middelink * * The pieces which added masquerading functionality are totally * my responsibility and have nothing to with the original authors * copyright or doing. * * Parts distributed under GPL. * * Fixes: * Pauline Middelink : Added masquerading. * Alan Cox : Fixed an error in the merge. * Thomas Quinot : Fixed port spoofing. * Alan Cox : Cleaned up retransmits in spoofing. * Alan Cox : Cleaned up length setting. * Wouter Gadeyne : Fixed masquerading support of ftp PORT commands * * Juan Jose Ciarlante : Masquerading code moved to ip_masq.c * Andi Kleen : Print frag_offsets and the ip flags properly. * * All the real work was done by ..... * *//* * 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. */#include <asm/uaccess.h>#include <asm/system.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/module.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/in.h>#include <linux/inet.h>#include <linux/netdevice.h>#include <linux/icmp.h>#include <linux/udp.h>#include <net/ip.h>#include <net/protocol.h>#include <net/route.h>#include <net/tcp.h>#include <net/udp.h>#include <net/sock.h>#include <net/icmp.h>#include <linux/netlink.h>#include <linux/init.h>#include <linux/spinlock.h>#include <linux/netfilter_ipv4/ipfwadm_core.h>#include <linux/netfilter_ipv4/compat_firewall.h>#include <linux/netfilter_ipv4/lockhelp.h>#include <linux/netfilter_ipv4/ip_nat_core.h>#include <net/checksum.h>#include <linux/proc_fs.h>#include <linux/stat.h>MODULE_LICENSE("Dual BSD/GPL");MODULE_DESCRIPTION("ipfwadm backwards compatibility layer");/* * Implement IP packet firewall */#ifdef DEBUG_IP_FIREWALL#define dprintf1(a) printk(a)#define dprintf2(a1,a2) printk(a1,a2)#define dprintf3(a1,a2,a3) printk(a1,a2,a3)#define dprintf4(a1,a2,a3,a4) printk(a1,a2,a3,a4)#else#define dprintf1(a)#define dprintf2(a1,a2)#define dprintf3(a1,a2,a3)#define dprintf4(a1,a2,a3,a4)#endif#define print_ip(a) printk("%u.%u.%u.%u", NIPQUAD(a));#ifdef DEBUG_IP_FIREWALL#define dprint_ip(a) print_ip(a)#else#define dprint_ip(a)#endifstatic DECLARE_RWLOCK(ip_fw_lock);#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)struct ip_fw *ip_fw_fwd_chain;struct ip_fw *ip_fw_in_chain;struct ip_fw *ip_fw_out_chain;struct ip_fw *ip_acct_chain;struct ip_fw *ip_masq_chain;static struct ip_fw **chains[] = {&ip_fw_fwd_chain, &ip_fw_in_chain, &ip_fw_out_chain, &ip_acct_chain, &ip_masq_chain };#endif /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */#ifdef CONFIG_IP_FIREWALLint ip_fw_fwd_policy=IP_FW_F_ACCEPT;int ip_fw_in_policy=IP_FW_F_ACCEPT;int ip_fw_out_policy=IP_FW_F_ACCEPT;static int *policies[] = {&ip_fw_fwd_policy, &ip_fw_in_policy, &ip_fw_out_policy};#endif#ifdef CONFIG_IP_FIREWALL_NETLINKstruct sock *ipfwsk;#endif/* * Returns 1 if the port is matched by the vector, 0 otherwise */extern inline int port_match(unsigned short *portptr,int nports,unsigned 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);}#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)#ifdef CONFIG_IP_FIREWALL_VERBOSE/* * VERY ugly piece of code which actually makes kernel printf for * matching packets. */static char *chain_name(struct ip_fw *chain, int mode){ switch (mode) { case IP_FW_MODE_ACCT_IN: return "acct in"; case IP_FW_MODE_ACCT_OUT: return "acct out"; default: if (chain == ip_fw_fwd_chain) return "fw-fwd"; else if (chain == ip_fw_in_chain) return "fw-in"; else return "fw-out"; }}static char *rule_name(struct ip_fw *f, int mode, char *buf){ if (mode == IP_FW_MODE_ACCT_IN || mode == IP_FW_MODE_ACCT_OUT) return ""; if(f->fw_flg&IP_FW_F_ACCEPT) { if(f->fw_flg&IP_FW_F_REDIR) { sprintf(buf, "acc/r%d ", f->fw_pts[f->fw_nsp+f->fw_ndp]); return buf; } else if(f->fw_flg&IP_FW_F_MASQ) return "acc/masq "; else return "acc "; } else if(f->fw_flg&IP_FW_F_ICMPRPL) { return "rej "; } else { return "deny "; }}static void print_packet(struct sk_buff **pskb, u16 src_port, u16 dst_port, u16 icmp_type, char *chain, char *rule, char *devname){ __u32 *opt = (__u32 *) ((*pskb)->nh.iph + 1); int opti; __u16 foff = ntohs((*pskb)->nh.iph->frag_off); int protocol = (*pskb)->nh.iph->protocol; printk(KERN_INFO "IP %s %s%s", chain, rule, devname); switch (protocol) { case IPPROTO_TCP: printk(" TCP "); break; case IPPROTO_UDP: printk(" UDP "); break; case IPPROTO_ICMP: printk(" ICMP/%d ", icmp_type); break; default: printk(" PROTO=%d ", protocol); break; }; print_ip((*pskb)->nh.iph->saddr); if (protocol == IPPROTO_TCP || protocol == IPPROTO_UDP) printk(":%hu", src_port); printk(" "); print_ip((*pskb)->nh.iph->daddr); if (protocol == IPPROTO_TCP || protocol == IPPROTO_UDP) printk(":%hu", dst_port); printk(" L=%hu S=0x%2.2hX I=%hu FO=0x%4.4hX T=%hu", ntohs((*pskb)->nh.iph->tot_len), (*pskb)->nh.iph->tos, ntohs((*pskb)->nh.iph->id), foff & IP_OFFSET, (*pskb)->nh.iph->ttl); if (foff & IP_DF) printk(" DF=1"); if (foff & IP_MF) printk(" MF=1"); for (opti = 0; opti < ((*pskb)->nh.iph->ihl - sizeof(struct iphdr) / 4); opti++) printk(" O=0x%8.8X", *opt++); printk("\n");}#endif/* * Returns one of the generic firewall policies, like FW_ACCEPT. * Also does accounting so you can feed it the accounting chain. * * The modes is either IP_FW_MODE_FW (normal firewall mode), * IP_FW_MODE_ACCT_IN or IP_FW_MODE_ACCT_OUT (accounting mode, * steps through the entire chain and handles fragments * differently), or IP_FW_MODE_CHK (handles user-level check, * counters are not updated). */int ip_fw_chk(struct sk_buff **pskb, struct net_device *rif, __u16 *redirport, struct ip_fw *chain, int policy, int mode){ struct ip_fw *f; __u32 src, dst; __u16 src_port=0xFFFF, dst_port=0xFFFF, icmp_type=0xFF; unsigned short f_prt=0, prt; char notcpsyn=0, notcpack=0, match; unsigned short offset; int answer; unsigned char tosand, tosxor; int protocol; /* * If the chain is empty follow policy. The BSD one * accepts anything giving you a time window while * flushing and rebuilding the tables. */ /* * This way we handle fragmented packets. * we ignore all fragments but the first one * so the whole packet can't be reassembled. * This way we relay on the full info which * stored only in first packet. * * Note that this theoretically allows partial packet * spoofing. Not very dangerous but paranoid people may * wish to play with this. It also allows the so called * "fragment bomb" denial of service attack on some types * of system. */ offset = ntohs((*pskb)->nh.iph->frag_off) & IP_OFFSET; protocol = (*pskb)->nh.iph->protocol; /* * Don't allow a fragment of TCP 8 bytes in. Nobody * normal causes this. Its a cracker trying to break * in by doing a flag overwrite to pass the direction * checks. */ if (offset == 1 && protocol == IPPROTO_TCP) return FW_BLOCK; if (offset!=0 && !(mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT)) && (protocol == IPPROTO_TCP || protocol == IPPROTO_UDP || protocol == IPPROTO_ICMP)) return FW_ACCEPT; /* * Header fragment for TCP is too small to check the bits. */ if (protocol == IPPROTO_TCP && ((*pskb)->nh.iph->ihl<<2)+16 > ntohs((*pskb)->nh.iph->tot_len)) return FW_BLOCK; /* * Too short. * * But only too short for a packet with ports... */ else if ((ntohs((*pskb)->nh.iph->tot_len) < 8 + ((*pskb)->nh.iph->ihl << 2)) && (protocol == IPPROTO_TCP || protocol == IPPROTO_UDP)) return FW_BLOCK; src = (*pskb)->nh.iph->saddr; dst = (*pskb)->nh.iph->daddr; /* * If we got interface from which packet came * we can use the address directly. This is unlike * 4.4BSD derived systems that have an address chain * per device. We have a device per address with dummy * devices instead. */ dprintf1("Packet "); switch (protocol) { case IPPROTO_TCP: dprintf1("TCP "); /* ports stay 0xFFFF if it is not the first fragment */ if (!offset) { struct tcphdr tcph; if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl * 4, &tcph, sizeof(tcph))) return FW_BLOCK; src_port = ntohs(tcph.source); dst_port = ntohs(tcph.dest); if(!tcph.ack && !tcph.rst) /* We do NOT have ACK, value TRUE */ notcpack = 1; if(!tcph.syn || !notcpack) /* We do NOT have SYN, value TRUE */ notcpsyn = 1; } prt = IP_FW_F_TCP; break; case IPPROTO_UDP: dprintf1("UDP "); /* ports stay 0xFFFF if it is not the first fragment */ if (!offset) { struct udphdr udph; if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl * 4, &udph, sizeof(udph))) return FW_BLOCK; src_port = ntohs(udph.source); dst_port = ntohs(udph.dest); } prt = IP_FW_F_UDP; break; case IPPROTO_ICMP: /* icmp_type stays 255 if it is not the first fragment */ if (!offset) { struct icmphdr icmph; if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl * 4, &icmph, sizeof(icmph))) return FW_BLOCK; icmp_type = (__u16) icmph.type; } dprintf2("ICMP:%d ", icmp_type); prt = IP_FW_F_ICMP; break; default: dprintf2("p=%d ", protocol); prt = IP_FW_F_ALL; break; }#ifdef DEBUG_IP_FIREWALL dprint_ip(src); if (protocol == IPPROTO_TCP || protocol == IPPROTO_UDP) /* This will print 65535 when it is not the first fragment! */ dprintf2(":%d ", src_port); dprint_ip(dst); if (protocol == IPPROTO_TCP || protocol == IPPROTO_UDP) /* This will print 65535 when it is not the first fragment! */ dprintf2(":%d ", dst_port); dprintf1("\n");#endif if (mode == IP_FW_MODE_CHK) READ_LOCK(&ip_fw_lock); else WRITE_LOCK(&ip_fw_lock); for (f = chain; f; f = f->fw_next) { /*
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -