Commit f631723a authored by Rusty Russell's avatar Rusty Russell Committed by Linus Torvalds

[PATCH] netfilter: Remove IPCHAINS and IPFWADM compatibility

We've been threatening to do this for ages: remove the backwards compatibility
code.  We can now combine ip_conntrack_core.c and ip_conntrack_standalone.c,
likewise for the NAT code, but that will come later.
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 6dd1537e
/* Minor modifications to fit on compatibility framework:
Rusty.Russell@rustcorp.com.au
*/
#ifndef __LINUX_FIREWALL_H
#define __LINUX_FIREWALL_H
/*
* Definitions for loadable firewall modules
*/
#define FW_QUEUE 0
#define FW_BLOCK 1
#define FW_ACCEPT 2
#define FW_REJECT (-1)
#define FW_REDIRECT 3
#define FW_MASQUERADE 4
#define FW_SKIP 5
struct firewall_ops
{
struct firewall_ops *next;
int (*fw_forward)(struct firewall_ops *this, int pf,
struct net_device *dev, void *arg,
struct sk_buff **pskb);
int (*fw_input)(struct firewall_ops *this, int pf,
struct net_device *dev, void *arg,
struct sk_buff **pskb);
int (*fw_output)(struct firewall_ops *this, int pf,
struct net_device *dev, void *arg,
struct sk_buff **pskb);
/* These may be NULL. */
int (*fw_acct_in)(struct firewall_ops *this, int pf,
struct net_device *dev, void *arg,
struct sk_buff **pskb);
int (*fw_acct_out)(struct firewall_ops *this, int pf,
struct net_device *dev, void *arg,
struct sk_buff **pskb);
};
extern int register_firewall(int pf, struct firewall_ops *fw);
extern int unregister_firewall(int pf, struct firewall_ops *fw);
extern int ip_fw_masq_timeouts(void *user, int len);
#endif /* __LINUX_FIREWALL_H */
/*
* This code is heavily based on the code in ip_fw.h; see that file for
* copyrights and attributions. This code is basically GPL.
*
* 15-Feb-1997: Major changes to allow graphs for firewall rules.
* Paul Russell <Paul.Russell@rustcorp.com.au> and
* Michael Neuling <Michael.Neuling@rustcorp.com.au>
* 2-Nov-1997: Changed types to __u16, etc.
* Removed IP_FW_F_TCPACK & IP_FW_F_BIDIR.
* Added inverse flags field.
* Removed multiple port specs.
*/
/*
* Format of an IP firewall descriptor
*
* src, dst, src_mask, dst_mask are always stored in network byte order.
* flags are stored in host byte order (of course).
* Port numbers are stored in HOST byte order.
*/
#ifndef _IP_FWCHAINS_H
#define _IP_FWCHAINS_H
#ifdef __KERNEL__
#include <linux/icmp.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#endif /* __KERNEL__ */
#define IP_FW_MAX_LABEL_LENGTH 8
typedef char ip_chainlabel[IP_FW_MAX_LABEL_LENGTH+1];
struct ip_fw
{
struct in_addr fw_src, fw_dst; /* Source and destination IP addr */
struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */
__u32 fw_mark; /* ID to stamp on packet */
__u16 fw_proto; /* Protocol, 0 = ANY */
__u16 fw_flg; /* Flags word */
__u16 fw_invflg; /* Inverse flags */
__u16 fw_spts[2]; /* Source port range. */
__u16 fw_dpts[2]; /* Destination port range. */
__u16 fw_redirpt; /* Port to redirect to. */
__u16 fw_outputsize; /* Max amount to output to
NETLINK */
char fw_vianame[IFNAMSIZ]; /* name of interface "via" */
__u8 fw_tosand, fw_tosxor; /* Revised packet priority */
};
struct ip_fwuser
{
struct ip_fw ipfw;
ip_chainlabel label;
};
/* Values for "fw_flg" field . */
#define IP_FW_F_PRN 0x0001 /* Print packet if it matches */
#define IP_FW_F_TCPSYN 0x0002 /* For tcp packets-check SYN only */
#define IP_FW_F_FRAG 0x0004 /* Set if rule is a fragment rule */
#define IP_FW_F_MARKABS 0x0008 /* Set the mark to fw_mark, not add. */
#define IP_FW_F_WILDIF 0x0010 /* Need only match start of interface name. */
#define IP_FW_F_NETLINK 0x0020 /* Redirect to netlink: 2.1.x only */
#define IP_FW_F_MASK 0x003F /* All possible flag bits mask */
/* Values for "fw_invflg" field. */
#define IP_FW_INV_SRCIP 0x0001 /* Invert the sense of fw_src. */
#define IP_FW_INV_DSTIP 0x0002 /* Invert the sense of fw_dst. */
#define IP_FW_INV_PROTO 0x0004 /* Invert the sense of fw_proto. */
#define IP_FW_INV_SRCPT 0x0008 /* Invert the sense of source ports. */
#define IP_FW_INV_DSTPT 0x0010 /* Invert the sense of destination ports. */
#define IP_FW_INV_VIA 0x0020 /* Invert the sense of fw_vianame. */
#define IP_FW_INV_SYN 0x0040 /* Invert the sense of IP_FW_F_TCPSYN. */
#define IP_FW_INV_FRAG 0x0080 /* Invert the sense of IP_FW_F_FRAG. */
/*
* New IP firewall options for [gs]etsockopt at the RAW IP level.
* Unlike BSD Linux inherits IP options so you don't have to use
* a raw socket for this. Instead we check rights in the calls. */
#define IP_FW_BASE_CTL 64 /* base for firewall socket options */
#define IP_FW_APPEND (IP_FW_BASE_CTL) /* Takes ip_fwchange */
#define IP_FW_REPLACE (IP_FW_BASE_CTL+1) /* Takes ip_fwnew */
#define IP_FW_DELETE_NUM (IP_FW_BASE_CTL+2) /* Takes ip_fwdelnum */
#define IP_FW_DELETE (IP_FW_BASE_CTL+3) /* Takes ip_fwchange */
#define IP_FW_INSERT (IP_FW_BASE_CTL+4) /* Takes ip_fwnew */
#define IP_FW_FLUSH (IP_FW_BASE_CTL+5) /* Takes ip_chainlabel */
#define IP_FW_ZERO (IP_FW_BASE_CTL+6) /* Takes ip_chainlabel */
#define IP_FW_CHECK (IP_FW_BASE_CTL+7) /* Takes ip_fwtest */
#define IP_FW_MASQ_TIMEOUTS (IP_FW_BASE_CTL+8) /* Takes 3 ints */
#define IP_FW_CREATECHAIN (IP_FW_BASE_CTL+9) /* Takes ip_chainlabel */
#define IP_FW_DELETECHAIN (IP_FW_BASE_CTL+10) /* Takes ip_chainlabel */
#define IP_FW_POLICY (IP_FW_BASE_CTL+11) /* Takes ip_fwpolicy */
/* Masquerade control, only 1 optname */
#define IP_FW_MASQ_CTL (IP_FW_BASE_CTL+12) /* General ip_masq ctl */
/* Builtin chain labels */
#define IP_FW_LABEL_FORWARD "forward"
#define IP_FW_LABEL_INPUT "input"
#define IP_FW_LABEL_OUTPUT "output"
/* Special targets */
#define IP_FW_LABEL_MASQUERADE "MASQ"
#define IP_FW_LABEL_REDIRECT "REDIRECT"
#define IP_FW_LABEL_ACCEPT "ACCEPT"
#define IP_FW_LABEL_BLOCK "DENY"
#define IP_FW_LABEL_REJECT "REJECT"
#define IP_FW_LABEL_RETURN "RETURN"
#define IP_FW_LABEL_QUEUE "QUEUE"
/* Files in /proc/net */
#define IP_FW_PROC_CHAINS "ip_fwchains"
#define IP_FW_PROC_CHAIN_NAMES "ip_fwnames"
struct ip_fwpkt
{
struct iphdr fwp_iph; /* IP header */
union {
struct tcphdr fwp_tcph; /* TCP header or */
struct udphdr fwp_udph; /* UDP header */
struct icmphdr fwp_icmph; /* ICMP header */
} fwp_protoh;
struct in_addr fwp_via; /* interface address */
char fwp_vianame[IFNAMSIZ]; /* interface name */
};
/* The argument to IP_FW_DELETE and IP_FW_APPEND */
struct ip_fwchange
{
struct ip_fwuser fwc_rule;
ip_chainlabel fwc_label;
};
/* The argument to IP_FW_CHECK. */
struct ip_fwtest
{
struct ip_fwpkt fwt_packet; /* Packet to be tested */
ip_chainlabel fwt_label; /* Block to start test in */
};
/* The argument to IP_FW_DELETE_NUM */
struct ip_fwdelnum
{
__u32 fwd_rulenum;
ip_chainlabel fwd_label;
};
/* The argument to IP_FW_REPLACE and IP_FW_INSERT */
struct ip_fwnew
{
__u32 fwn_rulenum;
struct ip_fwuser fwn_rule;
ip_chainlabel fwn_label;
};
/* The argument to IP_FW_POLICY */
struct ip_fwpolicy
{
ip_chainlabel fwp_policy;
ip_chainlabel fwp_label;
};
/*
* timeouts for ip masquerading
*/
extern int ip_fw_masq_timeouts(void *, int);
/*
* Main firewall chains definitions and global var's definitions.
*/
#ifdef __KERNEL__
#include <linux/config.h>
#include <linux/version.h>
#include <linux/init.h>
extern void ip_fw_init(void) __init;
extern int ip_fw_ctl(int, void *, int);
#ifdef CONFIG_IP_MASQUERADE
extern int ip_masq_uctl(int, char *, int);
#endif
#endif /* KERNEL */
#endif /* _IP_FWCHAINS_H */
#ifndef _IPFWADM_CORE_H
#define _IPFWADM_CORE_H
/* Minor modifications to fit on compatibility framework:
Rusty.Russell@rustcorp.com.au
*/
/*
* 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.
*
* Ported from BSD to Linux,
* Alan Cox 22/Nov/1994.
* 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.
*
* Fixes:
* Pauline Middelink : Added masquerading.
* Jos Vos : Separate input and output firewall
* chains, new "insert" and "append"
* commands to replace "add" commands,
* add ICMP header to struct ip_fwpkt.
* Jos Vos : Add support for matching device names.
* Willy Konynenberg : Add transparent proxying support.
* Jos Vos : Add options for input/output accounting.
*
* 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.
*/
/*
* Format of an IP firewall descriptor
*
* src, dst, src_mask, dst_mask are always stored in network byte order.
* flags and num_*_ports are stored in host byte order (of course).
* Port numbers are stored in HOST byte order.
*/
#ifdef __KERNEL__
#include <linux/icmp.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#endif
struct ip_fw
{
struct ip_fw *fw_next; /* Next firewall on chain */
struct in_addr fw_src, fw_dst; /* Source and destination IP addr */
struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */
struct in_addr fw_via; /* IP address of interface "via" */
struct net_device *fw_viadev; /* device of interface "via" */
__u16 fw_flg; /* Flags word */
__u16 fw_nsp, fw_ndp; /* N'of src ports and # of dst ports */
/* in ports array (dst ports follow */
/* src ports; max of 10 ports in all; */
/* count of 0 means match all ports) */
#define IP_FW_MAX_PORTS 10 /* A reasonable maximum */
__u16 fw_pts[IP_FW_MAX_PORTS]; /* Array of port numbers to match */
unsigned long fw_pcnt,fw_bcnt; /* Packet and byte counters */
__u8 fw_tosand, fw_tosxor; /* Revised packet priority */
char fw_vianame[IFNAMSIZ]; /* name of interface "via" */
};
/*
* Values for "flags" field .
*/
#define IP_FW_F_ALL 0x0000 /* This is a universal packet firewall*/
#define IP_FW_F_TCP 0x0001 /* This is a TCP packet firewall */
#define IP_FW_F_UDP 0x0002 /* This is a UDP packet firewall */
#define IP_FW_F_ICMP 0x0003 /* This is a ICMP packet firewall */
#define IP_FW_F_KIND 0x0003 /* Mask to isolate firewall kind */
#define IP_FW_F_ACCEPT 0x0004 /* This is an accept firewall (as *
* opposed to a deny firewall)*
* */
#define IP_FW_F_SRNG 0x0008 /* The first two src ports are a min *
* and max range (stored in host byte *
* order). *
* */
#define IP_FW_F_DRNG 0x0010 /* The first two dst ports are a min *
* and max range (stored in host byte *
* order). *
* (ports[0] <= port <= ports[1]) *
* */
#define IP_FW_F_PRN 0x0020 /* In verbose mode print this firewall*/
#define IP_FW_F_BIDIR 0x0040 /* For bidirectional firewalls */
#define IP_FW_F_TCPSYN 0x0080 /* For tcp packets-check SYN only */
#define IP_FW_F_ICMPRPL 0x0100 /* Send back icmp unreachable packet */
#define IP_FW_F_MASQ 0x0200 /* Masquerading */
#define IP_FW_F_TCPACK 0x0400 /* For tcp-packets match if ACK is set*/
#define IP_FW_F_REDIR 0x0800 /* Redirect to local port fw_pts[n] */
#define IP_FW_F_ACCTIN 0x1000 /* Account incoming packets only. */
#define IP_FW_F_ACCTOUT 0x2000 /* Account outgoing packets only. */
#define IP_FW_F_MASK 0x3FFF /* All possible flag bits mask */
/*
* New IP firewall options for [gs]etsockopt at the RAW IP level.
* Unlike BSD Linux inherits IP options so you don't have to use
* a raw socket for this. Instead we check rights in the calls.
*/
#define IP_FW_BASE_CTL 64 /* base for firewall socket options */
#define IP_FW_COMMAND 0x00FF /* mask for command without chain */
#define IP_FW_TYPE 0x0300 /* mask for type (chain) */
#define IP_FW_SHIFT 8 /* shift count for type (chain) */
#define IP_FW_FWD 0
#define IP_FW_IN 1
#define IP_FW_OUT 2
#define IP_FW_ACCT 3
#define IP_FW_CHAINS 4 /* total number of ip_fw chains */
#define IP_FW_MASQ 5
#define IP_FW_INSERT (IP_FW_BASE_CTL)
#define IP_FW_APPEND (IP_FW_BASE_CTL+1)
#define IP_FW_DELETE (IP_FW_BASE_CTL+2)
#define IP_FW_FLUSH (IP_FW_BASE_CTL+3)
#define IP_FW_ZERO (IP_FW_BASE_CTL+4)
#define IP_FW_POLICY (IP_FW_BASE_CTL+5)
#define IP_FW_CHECK (IP_FW_BASE_CTL+6)
#define IP_FW_MASQ_TIMEOUTS (IP_FW_BASE_CTL+7)
#define IP_FW_INSERT_FWD (IP_FW_INSERT | (IP_FW_FWD << IP_FW_SHIFT))
#define IP_FW_APPEND_FWD (IP_FW_APPEND | (IP_FW_FWD << IP_FW_SHIFT))
#define IP_FW_DELETE_FWD (IP_FW_DELETE | (IP_FW_FWD << IP_FW_SHIFT))
#define IP_FW_FLUSH_FWD (IP_FW_FLUSH | (IP_FW_FWD << IP_FW_SHIFT))
#define IP_FW_ZERO_FWD (IP_FW_ZERO | (IP_FW_FWD << IP_FW_SHIFT))
#define IP_FW_POLICY_FWD (IP_FW_POLICY | (IP_FW_FWD << IP_FW_SHIFT))
#define IP_FW_CHECK_FWD (IP_FW_CHECK | (IP_FW_FWD << IP_FW_SHIFT))
#define IP_FW_INSERT_IN (IP_FW_INSERT | (IP_FW_IN << IP_FW_SHIFT))
#define IP_FW_APPEND_IN (IP_FW_APPEND | (IP_FW_IN << IP_FW_SHIFT))
#define IP_FW_DELETE_IN (IP_FW_DELETE | (IP_FW_IN << IP_FW_SHIFT))
#define IP_FW_FLUSH_IN (IP_FW_FLUSH | (IP_FW_IN << IP_FW_SHIFT))
#define IP_FW_ZERO_IN (IP_FW_ZERO | (IP_FW_IN << IP_FW_SHIFT))
#define IP_FW_POLICY_IN (IP_FW_POLICY | (IP_FW_IN << IP_FW_SHIFT))
#define IP_FW_CHECK_IN (IP_FW_CHECK | (IP_FW_IN << IP_FW_SHIFT))
#define IP_FW_INSERT_OUT (IP_FW_INSERT | (IP_FW_OUT << IP_FW_SHIFT))
#define IP_FW_APPEND_OUT (IP_FW_APPEND | (IP_FW_OUT << IP_FW_SHIFT))
#define IP_FW_DELETE_OUT (IP_FW_DELETE | (IP_FW_OUT << IP_FW_SHIFT))
#define IP_FW_FLUSH_OUT (IP_FW_FLUSH | (IP_FW_OUT << IP_FW_SHIFT))
#define IP_FW_ZERO_OUT (IP_FW_ZERO | (IP_FW_OUT << IP_FW_SHIFT))
#define IP_FW_POLICY_OUT (IP_FW_POLICY | (IP_FW_OUT << IP_FW_SHIFT))
#define IP_FW_CHECK_OUT (IP_FW_CHECK | (IP_FW_OUT << IP_FW_SHIFT))
#define IP_ACCT_INSERT (IP_FW_INSERT | (IP_FW_ACCT << IP_FW_SHIFT))
#define IP_ACCT_APPEND (IP_FW_APPEND | (IP_FW_ACCT << IP_FW_SHIFT))
#define IP_ACCT_DELETE (IP_FW_DELETE | (IP_FW_ACCT << IP_FW_SHIFT))
#define IP_ACCT_FLUSH (IP_FW_FLUSH | (IP_FW_ACCT << IP_FW_SHIFT))
#define IP_ACCT_ZERO (IP_FW_ZERO | (IP_FW_ACCT << IP_FW_SHIFT))
#define IP_FW_MASQ_INSERT (IP_FW_INSERT | (IP_FW_MASQ << IP_FW_SHIFT))
#define IP_FW_MASQ_ADD (IP_FW_APPEND | (IP_FW_MASQ << IP_FW_SHIFT))
#define IP_FW_MASQ_DEL (IP_FW_DELETE | (IP_FW_MASQ << IP_FW_SHIFT))
#define IP_FW_MASQ_FLUSH (IP_FW_FLUSH | (IP_FW_MASQ << IP_FW_SHIFT))
#define IP_FW_MASQ_INSERT (IP_FW_INSERT | (IP_FW_MASQ << IP_FW_SHIFT))
#define IP_FW_MASQ_ADD (IP_FW_APPEND | (IP_FW_MASQ << IP_FW_SHIFT))
#define IP_FW_MASQ_DEL (IP_FW_DELETE | (IP_FW_MASQ << IP_FW_SHIFT))
#define IP_FW_MASQ_FLUSH (IP_FW_FLUSH | (IP_FW_MASQ << IP_FW_SHIFT))
struct ip_fwpkt
{
struct iphdr fwp_iph; /* IP header */
union {
struct tcphdr fwp_tcph; /* TCP header or */
struct udphdr fwp_udph; /* UDP header */
struct icmphdr fwp_icmph; /* ICMP header */
} fwp_protoh;
struct in_addr fwp_via; /* interface address */
char fwp_vianame[IFNAMSIZ]; /* interface name */
};
#define IP_FW_MASQCTL_MAX 256
#define IP_MASQ_MOD_NMAX 32
struct ip_fw_masqctl
{
int mctl_action;
union {
struct {
char name[IP_MASQ_MOD_NMAX];
char data[1];
} mod;
} u;
};
/*
* timeouts for ip masquerading
*/
struct ip_fw_masq;
/*
* Main firewall chains definitions and global var's definitions.
*/
#ifdef __KERNEL__
/* Modes used in the ip_fw_chk() routine. */
#define IP_FW_MODE_FW 0x00 /* kernel firewall check */
#define IP_FW_MODE_ACCT_IN 0x01 /* accounting (incoming) */
#define IP_FW_MODE_ACCT_OUT 0x02 /* accounting (outgoing) */
#define IP_FW_MODE_CHK 0x04 /* check requested by user */
#include <linux/config.h>
#ifdef CONFIG_IP_FIREWALL
extern struct ip_fw *ip_fw_in_chain;
extern struct ip_fw *ip_fw_out_chain;
extern struct ip_fw *ip_fw_fwd_chain;
extern int ip_fw_in_policy;
extern int ip_fw_out_policy;
extern int ip_fw_fwd_policy;
extern int ip_fw_ctl(int, void *, int);
#endif
#ifdef CONFIG_IP_ACCT
extern struct ip_fw *ip_acct_chain;
extern int ip_acct_ctl(int, void *, int);
#endif
#ifdef CONFIG_IP_MASQUERADE
extern int ip_masq_ctl(int, void *, int);
#endif
#ifdef CONFIG_IP_MASQUERADE
extern int ip_masq_ctl(int, void *, int);
#endif
extern int ip_fw_masq_timeouts(void *user, int len);
extern int ip_fw_chk(struct sk_buff **, struct net_device *, __u16 *,
struct ip_fw *, int, int);
#endif /* KERNEL */
#endif /* _IP_FW_H */
......@@ -458,7 +458,7 @@ config IP_NF_NAT
config IP_NF_NAT_NEEDED
bool
depends on IP_NF_CONNTRACK!=y && IP_NF_IPTABLES!=y && (IP_NF_COMPAT_IPCHAINS!=y && IP_NF_COMPAT_IPFWADM || IP_NF_COMPAT_IPCHAINS) || IP_NF_IPTABLES && IP_NF_CONNTRACK && IP_NF_NAT
depends on IP_NF_NAT != n
default y
config IP_NF_TARGET_MASQUERADE
......@@ -693,30 +693,5 @@ config IP_NF_ARP_MANGLE
Allows altering the ARP packet payload: source and destination
hardware and network addresses.
# Backwards compatibility modules: only if you don't build in the others.
config IP_NF_COMPAT_IPCHAINS
tristate "ipchains (2.2-style) support"
depends on IP_NF_CONNTRACK!=y && IP_NF_IPTABLES!=y
help
This option places ipchains (with masquerading and redirection
support) back into the kernel, using the new netfilter
infrastructure. It is not recommended for new installations (see
`Packet filtering'). With this enabled, you should be able to use
the ipchains tool exactly as in 2.2 kernels.
To compile it as a module, choose M here. If unsure, say N.
config IP_NF_COMPAT_IPFWADM
tristate "ipfwadm (2.0-style) support"
depends on IP_NF_CONNTRACK!=y && IP_NF_IPTABLES!=y && IP_NF_COMPAT_IPCHAINS!=y
help
This option places ipfwadm (with masquerading and redirection
support) back into the kernel, using the new netfilter
infrastructure. It is not recommended for new installations (see
`Packet filtering'). With this enabled, you should be able to use
the ipfwadm tool exactly as in 2.0 kernels.
To compile it as a module, choose M here. If unsure, say N.
endmenu
......@@ -2,19 +2,9 @@
# Makefile for the netfilter modules on top of IPv4.
#
# objects for the conntrack and NAT core (used by standalone and backw. compat)
ip_nf_conntrack-objs := ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o
ip_nf_nat-objs := ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
# objects for the standalone - connection tracking / NAT
ip_conntrack-objs := ip_conntrack_standalone.o $(ip_nf_conntrack-objs)
iptable_nat-objs := ip_nat_standalone.o ip_nat_rule.o $(ip_nf_nat-objs)
# objects for backwards compatibility mode
ip_nf_compat-objs := ip_fw_compat.o ip_fw_compat_redir.o ip_fw_compat_masq.o $(ip_nf_conntrack-objs) $(ip_nf_nat-objs)
ipfwadm-objs := $(ip_nf_compat-objs) ipfwadm_core.o
ipchains-objs := $(ip_nf_compat-objs) ipchains_core.o
ip_conntrack-objs := ip_conntrack_standalone.o ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o
iptable_nat-objs := ip_nat_standalone.o ip_nat_rule.o ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
# connection tracking
obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
......@@ -96,8 +86,4 @@ obj-$(CONFIG_IP_NF_ARP_MANGLE) += arpt_mangle.o
# just filtering instance of ARP tables for now
obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o
# backwards compatibility
obj-$(CONFIG_IP_NF_COMPAT_IPCHAINS) += ipchains.o
obj-$(CONFIG_IP_NF_COMPAT_IPFWADM) += ipfwadm.o
obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o
/* Compatibility framework for ipchains and ipfwadm support; designed
to look as much like the 2.2 infrastructure as possible. */
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
struct notifier_block;
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <net/icmp.h>
#include <linux/if.h>
#include <linux/inetdevice.h>
#include <linux/netdevice.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <net/ip.h>
#include <net/route.h>
#include <linux/netfilter_ipv4/compat_firewall.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <linux/netfilter_ipv4/ip_conntrack_core.h>
#include "ip_fw_compat.h"
static struct firewall_ops *fwops;
#ifdef CONFIG_IP_VS
/* From ip_vs_core.c */
extern unsigned int
check_for_ip_vs_out(struct sk_buff **skb_p, int (*okfn)(struct sk_buff *));
#endif
/* They call these; we do what they want. */
int register_firewall(int pf, struct firewall_ops *fw)
{
if (pf != PF_INET) {
printk("Attempt to register non-IP firewall module.\n");
return -EINVAL;
}
if (fwops) {
printk("Attempt to register multiple firewall modules.\n");
return -EBUSY;
}
fwops = fw;
return 0;
}
int unregister_firewall(int pf, struct firewall_ops *fw)
{
fwops = NULL;
return 0;
}
static unsigned int
fw_in(unsigned int hooknum,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
int ret = FW_BLOCK;
u_int16_t redirpt;
/* Assume worse case: any hook could change packet */
(*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED;
if ((*pskb)->ip_summed == CHECKSUM_HW)
if (skb_checksum_help(*pskb, (out == NULL)))
return NF_DROP;
switch (hooknum) {
case NF_IP_PRE_ROUTING:
if (fwops->fw_acct_in)
fwops->fw_acct_in(fwops, PF_INET,
(struct net_device *)in,
&redirpt, pskb);
if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
*pskb = ip_ct_gather_frags(*pskb);
if (!*pskb)
return NF_STOLEN;
}
ret = fwops->fw_input(fwops, PF_INET, (struct net_device *)in,
&redirpt, pskb);
break;
case NF_IP_FORWARD:
/* Connection will only be set if it was
demasqueraded: if so, skip forward chain. */
if ((*pskb)->nfct)
ret = FW_ACCEPT;
else ret = fwops->fw_forward(fwops, PF_INET,
(struct net_device *)out,
&redirpt, pskb);
break;
case NF_IP_POST_ROUTING:
ret = fwops->fw_output(fwops, PF_INET,
(struct net_device *)out,
&redirpt, pskb);
if (ret == FW_ACCEPT || ret == FW_SKIP) {
if (fwops->fw_acct_out)
fwops->fw_acct_out(fwops, PF_INET,
(struct net_device *)out,
&redirpt,
pskb);
/* ip_conntrack_confirm return NF_DROP or NF_ACCEPT */
if (ip_conntrack_confirm(*pskb) == NF_DROP)
ret = FW_BLOCK;
}
break;
}
switch (ret) {
case FW_REJECT: {
/* Alexey says:
*
* Generally, routing is THE FIRST thing to make, when
* packet enters IP stack. Before packet is routed you
* cannot call any service routines from IP stack. */
struct iphdr *iph = (*pskb)->nh.iph;
if ((*pskb)->dst != NULL
|| ip_route_input(*pskb, iph->daddr, iph->saddr, iph->tos,
(struct net_device *)in) == 0)
icmp_send(*pskb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH,
0);
return NF_DROP;
}
case FW_ACCEPT:
case FW_SKIP:
if (hooknum == NF_IP_PRE_ROUTING) {
check_for_demasq(pskb);
check_for_redirect(*pskb);
} else if (hooknum == NF_IP_POST_ROUTING) {
check_for_unredirect(*pskb);
/* Handle ICMP errors from client here */
if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
&& (*pskb)->nfct)
check_for_masq_error(pskb);
}
return NF_ACCEPT;
case FW_MASQUERADE:
if (hooknum == NF_IP_FORWARD) {
#ifdef CONFIG_IP_VS
/* check if it is for ip_vs */
if (check_for_ip_vs_out(pskb, okfn) == NF_STOLEN)
return NF_STOLEN;
#endif
return do_masquerade(pskb, out);
}
else return NF_ACCEPT;
case FW_REDIRECT:
if (hooknum == NF_IP_PRE_ROUTING)
return do_redirect(*pskb, in, redirpt);
else return NF_ACCEPT;
default:
/* FW_BLOCK */
return NF_DROP;
}
}
static unsigned int fw_confirm(unsigned int hooknum,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return ip_conntrack_confirm(*pskb);
}
extern int ip_fw_ctl(int optval, void *m, unsigned int len);
static int sock_fn(struct sock *sk, int optval, void __user *user, unsigned int len)
{
/* MAX of:
2.2: sizeof(struct ip_fwtest) (~14x4 + 3x4 = 17x4)
2.2: sizeof(struct ip_fwnew) (~1x4 + 15x4 + 3x4 + 3x4 = 22x4)
2.0: sizeof(struct ip_fw) (~25x4)
We can't include both 2.0 and 2.2 headers, they conflict.
Hence, 200 is a good number. --RR */
char tmp_fw[200];
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (len > sizeof(tmp_fw) || len < 1)
return -EINVAL;
if (copy_from_user(&tmp_fw, user, len))
return -EFAULT;
return -ip_fw_ctl(optval, &tmp_fw, len);
}
static struct nf_hook_ops preroute_ops = {
.hook = fw_in,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_PRE_ROUTING,
.priority = NF_IP_PRI_FILTER,
};
static struct nf_hook_ops postroute_ops = {
.hook = fw_in,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_POST_ROUTING,
.priority = NF_IP_PRI_FILTER,
};
static struct nf_hook_ops forward_ops = {
.hook = fw_in,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_FORWARD,
.priority = NF_IP_PRI_FILTER,
};
static struct nf_hook_ops local_in_ops = {
.hook = fw_confirm,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_LOCAL_IN,
.priority = NF_IP_PRI_LAST - 1,
};
static struct nf_sockopt_ops sock_ops = {
.pf = PF_INET,
.set_optmin = 64,
.set_optmax = 64 + 1024 + 1,
.set = &sock_fn,
};
extern int ipfw_init_or_cleanup(int init);
static int init_or_cleanup(int init)
{
int ret = 0;
if (!init) goto cleanup;
ret = nf_register_sockopt(&sock_ops);
if (ret < 0)
goto cleanup_nothing;
ret = ipfw_init_or_cleanup(1);
if (ret < 0)
goto cleanup_sockopt;
ret = masq_init();
if (ret < 0)
goto cleanup_ipfw;
nf_register_hook(&preroute_ops);
nf_register_hook(&postroute_ops);
nf_register_hook(&forward_ops);
nf_register_hook(&local_in_ops);
return ret;
cleanup:
nf_unregister_hook(&preroute_ops);
nf_unregister_hook(&postroute_ops);
nf_unregister_hook(&forward_ops);
nf_unregister_hook(&local_in_ops);
masq_cleanup();
cleanup_ipfw:
ipfw_init_or_cleanup(0);
cleanup_sockopt:
nf_unregister_sockopt(&sock_ops);
cleanup_nothing:
return ret;
}
static int __init init(void)
{
return init_or_cleanup(1);
}
static void __exit fini(void)
{
init_or_cleanup(0);
}
module_init(init);
module_exit(fini);
#ifndef _LINUX_IP_FW_COMPAT_H
#define _LINUX_IP_FW_COMPAT_H
/* From ip_fw_compat_redir.c */
extern unsigned int
do_redirect(struct sk_buff *skb,
const struct net_device *dev,
u_int16_t redirpt);
extern void
check_for_redirect(struct sk_buff *skb);
extern void
check_for_unredirect(struct sk_buff *skb);
/* From ip_fw_compat_masq.c */
extern unsigned int
do_masquerade(struct sk_buff **pskb, const struct net_device *dev);
extern void check_for_masq_error(struct sk_buff **pskb);
extern unsigned int
check_for_demasq(struct sk_buff **pskb);
extern int __init masq_init(void);
extern void masq_cleanup(void);
#endif /* _LINUX_IP_FW_COMPAT_H */
/* Masquerading compatibility layer.
Note that there are no restrictions on other programs binding to
ports 61000:65095 (in 2.0 and 2.2 they get EADDRINUSE). Just DON'T
DO IT.
*/
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/icmp.h>
#include <linux/udp.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/proc_fs.h>
#include <linux/module.h>
#include <net/route.h>
#include <net/ip.h>
#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <linux/netfilter_ipv4/ip_conntrack_core.h>
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
#include <linux/netfilter_ipv4/ip_nat.h>
#include <linux/netfilter_ipv4/ip_nat_core.h>
#include <linux/netfilter_ipv4/listhelp.h>
#include "ip_fw_compat.h"
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
unsigned int
do_masquerade(struct sk_buff **pskb, const struct net_device *dev)
{
struct ip_nat_info *info;
enum ip_conntrack_info ctinfo;
struct ip_conntrack *ct;
unsigned int ret;
/* Sorry, only ICMP, TCP and UDP. */
if ((*pskb)->nh.iph->protocol != IPPROTO_ICMP
&& (*pskb)->nh.iph->protocol != IPPROTO_TCP
&& (*pskb)->nh.iph->protocol != IPPROTO_UDP)
return NF_DROP;
/* Feed it to connection tracking; in fact we're in NF_IP_FORWARD,
but connection tracking doesn't expect that */
ret = ip_conntrack_in(NF_IP_POST_ROUTING, pskb, dev, NULL, NULL);
if (ret != NF_ACCEPT) {
DEBUGP("ip_conntrack_in returned %u.\n", ret);
return ret;
}
ct = ip_conntrack_get(*pskb, &ctinfo);
if (!ct) {
DEBUGP("ip_conntrack_in set to invalid conntrack.\n");
return NF_DROP;
}
info = &ct->nat.info;
WRITE_LOCK(&ip_nat_lock);
/* Setup the masquerade, if not already */
if (!info->initialized) {
u_int32_t newsrc;
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = (*pskb)->nh.iph->daddr } } };
struct rtable *rt;
struct ip_nat_multi_range range;
/* Pass 0 instead of saddr, since it's going to be changed
anyway. */
if (ip_route_output_key(&rt, &fl) != 0) {
DEBUGP("ipnat_rule_masquerade: Can't reroute.\n");
return NF_DROP;
}
newsrc = inet_select_addr(rt->u.dst.dev, rt->rt_gateway,
RT_SCOPE_UNIVERSE);
ip_rt_put(rt);
range = ((struct ip_nat_multi_range)
{ 1,
{{IP_NAT_RANGE_MAP_IPS|IP_NAT_RANGE_PROTO_SPECIFIED,
newsrc, newsrc,
{ htons(61000) }, { htons(65095) } } } });
ret = ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
if (ret != NF_ACCEPT) {
WRITE_UNLOCK(&ip_nat_lock);
return ret;
}
} else
DEBUGP("Masquerading already done on this conn.\n");
WRITE_UNLOCK(&ip_nat_lock);
return do_bindings(ct, ctinfo, info, NF_IP_POST_ROUTING, pskb);
}
void
check_for_masq_error(struct sk_buff **pskb)
{
enum ip_conntrack_info ctinfo;
struct ip_conntrack *ct;
ct = ip_conntrack_get(*pskb, &ctinfo);
/* Wouldn't be here if not tracked already => masq'ed ICMP
ping or error related to masq'd connection */
IP_NF_ASSERT(ct);
if (ctinfo == IP_CT_RELATED) {
icmp_reply_translation(pskb, ct, NF_IP_PRE_ROUTING,
CTINFO2DIR(ctinfo));
icmp_reply_translation(pskb, ct, NF_IP_POST_ROUTING,
CTINFO2DIR(ctinfo));
}
}
unsigned int
check_for_demasq(struct sk_buff **pskb)
{
struct ip_conntrack_tuple tuple;
struct ip_conntrack_protocol *protocol;
struct ip_conntrack_tuple_hash *h;
enum ip_conntrack_info ctinfo;
struct ip_conntrack *ct;
int ret;
protocol = ip_ct_find_proto((*pskb)->nh.iph->protocol);
/* We don't feed packets to conntrack system unless we know
they're part of an connection already established by an
explicit masq command. */
switch ((*pskb)->nh.iph->protocol) {
case IPPROTO_ICMP:
/* ICMP errors. */
protocol->error(*pskb, &ctinfo, NF_IP_PRE_ROUTING);
ct = (struct ip_conntrack *)(*pskb)->nfct;
if (ct) {
/* We only do SNAT in the compatibility layer.
So we can manipulate ICMP errors from
server here (== DNAT). Do SNAT icmp manips
in POST_ROUTING handling. */
if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
icmp_reply_translation(pskb, ct,
NF_IP_PRE_ROUTING,
CTINFO2DIR(ctinfo));
icmp_reply_translation(pskb, ct,
NF_IP_POST_ROUTING,
CTINFO2DIR(ctinfo));
}
return NF_ACCEPT;
}
/* Fall thru... */
case IPPROTO_TCP:
case IPPROTO_UDP:
IP_NF_ASSERT(((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
if (!ip_ct_get_tuple((*pskb)->nh.iph, *pskb,
(*pskb)->nh.iph->ihl*4, &tuple, protocol)) {
if (net_ratelimit())
printk("ip_fw_compat_masq: Can't get tuple\n");
return NF_ACCEPT;
}
break;
default:
/* Not ours... */
return NF_ACCEPT;
}
h = ip_conntrack_find_get(&tuple, NULL);
/* MUST be found, and MUST be reply. */
if (h && DIRECTION(h) == 1) {
ret = ip_conntrack_in(NF_IP_PRE_ROUTING, pskb,
NULL, NULL, NULL);
/* Put back the reference gained from find_get */
nf_conntrack_put(&h->ctrack->ct_general);
if (ret == NF_ACCEPT) {
struct ip_conntrack *ct;
ct = ip_conntrack_get(*pskb, &ctinfo);
if (ct) {
struct ip_nat_info *info = &ct->nat.info;
do_bindings(ct, ctinfo, info,
NF_IP_PRE_ROUTING,
pskb);
} else
if (net_ratelimit())
printk("ip_fw_compat_masq: conntrack"
" didn't like\n");
}
} else {
if (h)
/* Put back the reference gained from find_get */
nf_conntrack_put(&h->ctrack->ct_general);
ret = NF_ACCEPT;
}
return ret;
}
int ip_fw_masq_timeouts(void *user, int len)
{
printk("Sorry: masquerading timeouts set 5DAYS/2MINS/60SECS\n");
return 0;
}
static const char *masq_proto_name(u_int16_t protonum)
{
switch (protonum) {
case IPPROTO_TCP: return "TCP";
case IPPROTO_UDP: return "UDP";
case IPPROTO_ICMP: return "ICMP";
default: return "MORE-CAFFEINE-FOR-RUSTY";
}
}
static unsigned int
print_masq(char *buffer, const struct ip_conntrack *conntrack)
{
char temp[129];
/* This is for backwards compatibility, but ick!.
We should never export jiffies to userspace.
*/
sprintf(temp,"%s %08X:%04X %08X:%04X %04X %08X %6d %6d %7lu",
masq_proto_name(conntrack->tuplehash[0].tuple.dst.protonum),
ntohl(conntrack->tuplehash[0].tuple.src.ip),
ntohs(conntrack->tuplehash[0].tuple.src.u.all),
ntohl(conntrack->tuplehash[0].tuple.dst.ip),
ntohs(conntrack->tuplehash[0].tuple.dst.u.all),
ntohs(conntrack->tuplehash[1].tuple.dst.u.all),
/* Sorry, no init_seq, delta or previous_delta (yet). */
0, 0, 0,
conntrack->timeout.expires - jiffies);
return sprintf(buffer, "%-127s\n", temp);
}
/* Returns true when finished. */
static int
masq_iterate(const struct ip_conntrack_tuple_hash *hash,
char *buffer, off_t offset, off_t *upto,
unsigned int *len, unsigned int maxlen)
{
unsigned int newlen;
IP_NF_ASSERT(hash->ctrack);
/* Only count originals */
if (DIRECTION(hash))
return 0;
if ((*upto)++ < offset)
return 0;
newlen = print_masq(buffer + *len, hash->ctrack);
if (*len + newlen > maxlen)
return 1;
else *len += newlen;
return 0;
}
/* Everything in the hash is masqueraded. */
static int
masq_procinfo(char *buffer, char **start, off_t offset, int length)
{
unsigned int i;
int len = 0;
off_t upto = 1;
/* Header: first record */
if (offset == 0) {
char temp[128];
sprintf(temp,
"Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta PDelta Expires (free=0,0,0)");
len = sprintf(buffer, "%-127s\n", temp);
offset = 1;
}
READ_LOCK(&ip_conntrack_lock);
/* Traverse hash; print originals then reply. */
for (i = 0; i < ip_conntrack_htable_size; i++) {
if (LIST_FIND(&ip_conntrack_hash[i], masq_iterate,
struct ip_conntrack_tuple_hash *,
buffer, offset, &upto, &len, length))
break;
}
READ_UNLOCK(&ip_conntrack_lock);
/* `start' hack - see fs/proc/generic.c line ~165 */
*start = (char *)((unsigned int)upto - offset);
return len;
}
int __init masq_init(void)
{
int ret;
struct proc_dir_entry *proc;
ret = ip_conntrack_init();
if (ret == 0) {
ret = ip_nat_init();
if (ret == 0) {
proc = proc_net_create("ip_masquerade",
0, masq_procinfo);
if (proc)
proc->owner = THIS_MODULE;
else {
ip_nat_cleanup();
ip_conntrack_cleanup();
ret = -ENOMEM;
}
} else
ip_conntrack_cleanup();
}
return ret;
}
void masq_cleanup(void)
{
ip_nat_cleanup();
ip_conntrack_cleanup();
proc_net_remove("ip_masquerade");
}
/* This is a file to handle the "simple" NAT cases (redirect and
masquerade) required for the compatibility layer.
`bind to foreign address' and `getpeername' hacks are not
supported.
FIXME: Timing is overly simplistic. If anyone complains, make it
use conntrack.
*/
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/config.h>
#include <linux/netfilter.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <net/checksum.h>
#include <net/ip.h>
#include <linux/timer.h>
#include <linux/netdevice.h>
#include <linux/if.h>
#include <linux/in.h>
#include <linux/netfilter_ipv4/lockhelp.h>
/* Very simple timeout pushed back by each packet */
#define REDIR_TIMEOUT (240*HZ)
static DECLARE_LOCK(redir_lock);
#define ASSERT_READ_LOCK(x) MUST_BE_LOCKED(&redir_lock)
#define ASSERT_WRITE_LOCK(x) MUST_BE_LOCKED(&redir_lock)
#include <linux/netfilter_ipv4/listhelp.h>
#include "ip_fw_compat.h"
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
#ifdef CONFIG_NETFILTER_DEBUG
#define IP_NF_ASSERT(x) \
do { \
if (!(x)) \
/* Wooah! I'm tripping my conntrack in a frenzy of \
netplay... */ \
printk("ASSERT: %s:%i(%s)\n", \
__FILE__, __LINE__, __FUNCTION__); \
} while(0)
#else
#define IP_NF_ASSERT(x)
#endif
static u_int16_t
cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
{
u_int32_t diffs[] = { oldvalinv, newval };
return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
oldcheck^0xFFFF));
}
struct redir_core {
u_int32_t orig_srcip, orig_dstip;
u_int16_t orig_sport, orig_dport;
u_int32_t new_dstip;
u_int16_t new_dport;
};
struct redir
{
struct list_head list;
struct redir_core core;
struct timer_list destroyme;
};
static LIST_HEAD(redirs);
static int
redir_cmp(const struct redir *i,
u_int32_t orig_srcip, u_int32_t orig_dstip,
u_int16_t orig_sport, u_int16_t orig_dport)
{
return (i->core.orig_srcip == orig_srcip
&& i->core.orig_dstip == orig_dstip
&& i->core.orig_sport == orig_sport
&& i->core.orig_dport == orig_dport);
}
/* Search for an existing redirection of the TCP packet. */
static struct redir *
find_redir(u_int32_t orig_srcip, u_int32_t orig_dstip,
u_int16_t orig_sport, u_int16_t orig_dport)
{
return LIST_FIND(&redirs, redir_cmp, struct redir *,
orig_srcip, orig_dstip, orig_sport, orig_dport);
}
static void do_tcp_redir(struct sk_buff *skb, struct redir *redir)
{
struct iphdr *iph = skb->nh.iph;
struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph
+ iph->ihl);
tcph->check = cheat_check(~redir->core.orig_dstip,
redir->core.new_dstip,
cheat_check(redir->core.orig_dport ^ 0xFFFF,
redir->core.new_dport,
tcph->check));
iph->check = cheat_check(~redir->core.orig_dstip,
redir->core.new_dstip, iph->check);
tcph->dest = redir->core.new_dport;
iph->daddr = redir->core.new_dstip;
skb->nfcache |= NFC_ALTERED;
}
static int
unredir_cmp(const struct redir *i,
u_int32_t new_dstip, u_int32_t orig_srcip,
u_int16_t new_dport, u_int16_t orig_sport)
{
return (i->core.orig_srcip == orig_srcip
&& i->core.new_dstip == new_dstip
&& i->core.orig_sport == orig_sport
&& i->core.new_dport == new_dport);
}
/* Match reply packet against redir */
static struct redir *
find_unredir(u_int32_t new_dstip, u_int32_t orig_srcip,
u_int16_t new_dport, u_int16_t orig_sport)
{
return LIST_FIND(&redirs, unredir_cmp, struct redir *,
new_dstip, orig_srcip, new_dport, orig_sport);
}
/* `unredir' a reply packet. */
static void do_tcp_unredir(struct sk_buff *skb, struct redir *redir)
{
struct iphdr *iph = skb->nh.iph;
struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph
+ iph->ihl);
tcph->check = cheat_check(~redir->core.new_dstip,
redir->core.orig_dstip,
cheat_check(redir->core.new_dport ^ 0xFFFF,
redir->core.orig_dport,
tcph->check));
iph->check = cheat_check(~redir->core.new_dstip,
redir->core.orig_dstip,
iph->check);
tcph->source = redir->core.orig_dport;
iph->saddr = redir->core.orig_dstip;
skb->nfcache |= NFC_ALTERED;
}
static void destroyme(unsigned long me)
{
LOCK_BH(&redir_lock);
LIST_DELETE(&redirs, (struct redir *)me);
UNLOCK_BH(&redir_lock);
kfree((struct redir *)me);
}
/* REDIRECT a packet. */
unsigned int
do_redirect(struct sk_buff *skb,
const struct net_device *dev,
u_int16_t redirpt)
{
struct iphdr *iph = skb->nh.iph;
u_int32_t newdst;
/* Figure out address: not loopback. */
if (!dev)
return NF_DROP;
/* Grab first address on interface. */
newdst = ((struct in_device *)dev->ip_ptr)->ifa_list->ifa_local;
switch (iph->protocol) {
case IPPROTO_UDP: {
/* Simple mangle. */
struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph
+ iph->ihl);
/* Must have whole header */
if (skb->len < iph->ihl*4 + sizeof(*udph))
return NF_DROP;
if (udph->check) /* 0 is a special case meaning no checksum */
udph->check = cheat_check(~iph->daddr, newdst,
cheat_check(udph->dest ^ 0xFFFF,
redirpt,
udph->check));
iph->check = cheat_check(~iph->daddr, newdst, iph->check);
udph->dest = redirpt;
iph->daddr = newdst;
skb->nfcache |= NFC_ALTERED;
return NF_ACCEPT;
}
case IPPROTO_TCP: {
/* Mangle, maybe record. */
struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph
+ iph->ihl);
struct redir *redir;
int ret;
/* Must have whole header */
if (skb->len < iph->ihl*4 + sizeof(*tcph))
return NF_DROP;
DEBUGP("Doing tcp redirect. %08X:%u %08X:%u -> %08X:%u\n",
iph->saddr, tcph->source, iph->daddr, tcph->dest,
newdst, redirpt);
LOCK_BH(&redir_lock);
redir = find_redir(iph->saddr, iph->daddr,
tcph->source, tcph->dest);
if (!redir) {
redir = kmalloc(sizeof(struct redir), GFP_ATOMIC);
if (!redir) {
ret = NF_DROP;
goto out;
}
list_prepend(&redirs, redir);
init_timer(&redir->destroyme);
redir->destroyme.function = destroyme;
redir->destroyme.data = (unsigned long)redir;
redir->destroyme.expires = jiffies + REDIR_TIMEOUT;
add_timer(&redir->destroyme);
}
/* In case mangling has changed, rewrite this part. */
redir->core = ((struct redir_core)
{ iph->saddr, iph->daddr,
tcph->source, tcph->dest,
newdst, redirpt });
do_tcp_redir(skb, redir);
ret = NF_ACCEPT;
out:
UNLOCK_BH(&redir_lock);
return ret;
}
default: /* give up if not TCP or UDP. */
return NF_DROP;
}
}
/* Incoming packet: is it a reply to a masqueraded connection, or
part of an already-redirected TCP connection? */
void
check_for_redirect(struct sk_buff *skb)
{
struct iphdr *iph = skb->nh.iph;
struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph
+ iph->ihl);
struct redir *redir;
if (iph->protocol != IPPROTO_TCP)
return;
/* Must have whole header */
if (skb->len < iph->ihl*4 + sizeof(*tcph))
return;
LOCK_BH(&redir_lock);
redir = find_redir(iph->saddr, iph->daddr, tcph->source, tcph->dest);
if (redir) {
DEBUGP("Doing tcp redirect again.\n");
do_tcp_redir(skb, redir);
if (del_timer(&redir->destroyme)) {
redir->destroyme.expires = jiffies + REDIR_TIMEOUT;
add_timer(&redir->destroyme);
}
}
UNLOCK_BH(&redir_lock);
}
void
check_for_unredirect(struct sk_buff *skb)
{
struct iphdr *iph = skb->nh.iph;
struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph
+ iph->ihl);
struct redir *redir;
if (iph->protocol != IPPROTO_TCP)
return;
/* Must have whole header */
if (skb->len < iph->ihl*4 + sizeof(*tcph))
return;
LOCK_BH(&redir_lock);
redir = find_unredir(iph->saddr, iph->daddr, tcph->source, tcph->dest);
if (redir) {
DEBUGP("Doing tcp unredirect.\n");
do_tcp_unredir(skb, redir);
if (del_timer(&redir->destroyme)) {
redir->destroyme.expires = jiffies + REDIR_TIMEOUT;
add_timer(&redir->destroyme);
}
}
UNLOCK_BH(&redir_lock);
}
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment