mirror of
https://github.com/torvalds/linux.git
synced 2024-12-25 20:32:22 +00:00
[NET]: The scheduled removal of the frame diverter.
This patch contains the scheduled removal of the frame diverter. Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
d7f7365f57
commit
90833aa4f4
@ -227,21 +227,6 @@ Who: Patrick McHardy <kaber@trash.net>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: frame diverter
|
||||
When: November 2006
|
||||
Why: The frame diverter is included in most distribution kernels, but is
|
||||
broken. It does not correctly handle many things:
|
||||
- IPV6
|
||||
- non-linear skb's
|
||||
- network device RCU on removal
|
||||
- input frames not correctly checked for protocol errors
|
||||
It also adds allocation overhead even if not enabled.
|
||||
It is not clear if anyone is still using it.
|
||||
Who: Stephen Hemminger <shemminger@osdl.org>
|
||||
|
||||
---------------------------
|
||||
|
||||
|
||||
What: PHYSDEVPATH, PHYSDEVBUS, PHYSDEVDRIVER in the uevent environment
|
||||
When: October 2008
|
||||
Why: The stacking of class devices makes these values misleading and
|
||||
|
@ -33,7 +33,6 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/divert.h>
|
||||
|
||||
/* A unified ethernet device probe. This is the easiest way to have every
|
||||
ethernet adaptor have the name "eth[0123...]".
|
||||
|
@ -193,7 +193,6 @@ unifdef-y += cuda.h
|
||||
unifdef-y += cyclades.h
|
||||
unifdef-y += dccp.h
|
||||
unifdef-y += dirent.h
|
||||
unifdef-y += divert.h
|
||||
unifdef-y += dlm.h
|
||||
unifdef-y += elfcore.h
|
||||
unifdef-y += errno.h
|
||||
|
@ -1,132 +0,0 @@
|
||||
/*
|
||||
* Frame Diversion, Benoit Locher <Benoit.Locher@skf.com>
|
||||
*
|
||||
* Changes:
|
||||
* 06/09/2000 BL: initial version
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_DIVERT_H
|
||||
#define _LINUX_DIVERT_H
|
||||
|
||||
#include <asm/types.h>
|
||||
|
||||
#define MAX_DIVERT_PORTS 8 /* Max number of ports to divert (tcp, udp) */
|
||||
|
||||
/* Divertable protocols */
|
||||
#define DIVERT_PROTO_NONE 0x0000
|
||||
#define DIVERT_PROTO_IP 0x0001
|
||||
#define DIVERT_PROTO_ICMP 0x0002
|
||||
#define DIVERT_PROTO_TCP 0x0004
|
||||
#define DIVERT_PROTO_UDP 0x0008
|
||||
|
||||
/*
|
||||
* This is an Ethernet Frame Diverter option block
|
||||
*/
|
||||
struct divert_blk
|
||||
{
|
||||
int divert; /* are we active */
|
||||
unsigned int protos; /* protocols */
|
||||
__u16 tcp_dst[MAX_DIVERT_PORTS]; /* specific tcp dst ports to divert */
|
||||
__u16 tcp_src[MAX_DIVERT_PORTS]; /* specific tcp src ports to divert */
|
||||
__u16 udp_dst[MAX_DIVERT_PORTS]; /* specific udp dst ports to divert */
|
||||
__u16 udp_src[MAX_DIVERT_PORTS]; /* specific udp src ports to divert */
|
||||
};
|
||||
|
||||
/*
|
||||
* Diversion control block, for configuration with the userspace tool
|
||||
* divert
|
||||
*/
|
||||
|
||||
typedef union _divert_cf_arg
|
||||
{
|
||||
__s16 int16;
|
||||
__u16 uint16;
|
||||
__s32 int32;
|
||||
__u32 uint32;
|
||||
__s64 int64;
|
||||
__u64 uint64;
|
||||
void __user *ptr;
|
||||
} divert_cf_arg;
|
||||
|
||||
|
||||
struct divert_cf
|
||||
{
|
||||
int cmd; /* Command */
|
||||
divert_cf_arg arg1,
|
||||
arg2,
|
||||
arg3;
|
||||
int dev_index; /* device index (eth0=0, etc...) */
|
||||
};
|
||||
|
||||
|
||||
/* Diversion commands */
|
||||
#define DIVCMD_DIVERT 1 /* ENABLE/DISABLE diversion */
|
||||
#define DIVCMD_IP 2 /* ENABLE/DISABLE whold IP diversion */
|
||||
#define DIVCMD_TCP 3 /* ENABLE/DISABLE whold TCP diversion */
|
||||
#define DIVCMD_TCPDST 4 /* ADD/REMOVE TCP DST port for diversion */
|
||||
#define DIVCMD_TCPSRC 5 /* ADD/REMOVE TCP SRC port for diversion */
|
||||
#define DIVCMD_UDP 6 /* ENABLE/DISABLE whole UDP diversion */
|
||||
#define DIVCMD_UDPDST 7 /* ADD/REMOVE UDP DST port for diversion */
|
||||
#define DIVCMD_UDPSRC 8 /* ADD/REMOVE UDP SRC port for diversion */
|
||||
#define DIVCMD_ICMP 9 /* ENABLE/DISABLE whole ICMP diversion */
|
||||
#define DIVCMD_GETSTATUS 10 /* GET the status of the diverter */
|
||||
#define DIVCMD_RESET 11 /* Reset the diverter on the specified dev */
|
||||
#define DIVCMD_GETVERSION 12 /* Retrieve the diverter code version (char[32]) */
|
||||
|
||||
/* General syntax of the commands:
|
||||
*
|
||||
* DIVCMD_xxxxxx(arg1, arg2, arg3, dev_index)
|
||||
*
|
||||
* SIOCSIFDIVERT:
|
||||
* DIVCMD_DIVERT(DIVARG1_ENABLE|DIVARG1_DISABLE, , ,ifindex)
|
||||
* DIVCMD_IP(DIVARG1_ENABLE|DIVARG1_DISABLE, , , ifindex)
|
||||
* DIVCMD_TCP(DIVARG1_ENABLE|DIVARG1_DISABLE, , , ifindex)
|
||||
* DIVCMD_TCPDST(DIVARG1_ADD|DIVARG1_REMOVE, port, , ifindex)
|
||||
* DIVCMD_TCPSRC(DIVARG1_ADD|DIVARG1_REMOVE, port, , ifindex)
|
||||
* DIVCMD_UDP(DIVARG1_ENABLE|DIVARG1_DISABLE, , , ifindex)
|
||||
* DIVCMD_UDPDST(DIVARG1_ADD|DIVARG1_REMOVE, port, , ifindex)
|
||||
* DIVCMD_UDPSRC(DIVARG1_ADD|DIVARG1_REMOVE, port, , ifindex)
|
||||
* DIVCMD_ICMP(DIVARG1_ENABLE|DIVARG1_DISABLE, , , ifindex)
|
||||
* DIVCMD_RESET(, , , ifindex)
|
||||
*
|
||||
* SIOGIFDIVERT:
|
||||
* DIVCMD_GETSTATUS(divert_blk, , , ifindex)
|
||||
* DIVCMD_GETVERSION(string[3])
|
||||
*/
|
||||
|
||||
|
||||
/* Possible values for arg1 */
|
||||
#define DIVARG1_ENABLE 0 /* ENABLE something */
|
||||
#define DIVARG1_DISABLE 1 /* DISABLE something */
|
||||
#define DIVARG1_ADD 2 /* ADD something */
|
||||
#define DIVARG1_REMOVE 3 /* REMOVE something */
|
||||
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/* diverter functions */
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#ifdef CONFIG_NET_DIVERT
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
int alloc_divert_blk(struct net_device *);
|
||||
void free_divert_blk(struct net_device *);
|
||||
int divert_ioctl(unsigned int cmd, struct divert_cf __user *arg);
|
||||
void divert_frame(struct sk_buff *skb);
|
||||
static inline void handle_diverter(struct sk_buff *skb)
|
||||
{
|
||||
/* if diversion is supported on device, then divert */
|
||||
if (skb->dev->divert && skb->dev->divert->divert)
|
||||
divert_frame(skb);
|
||||
}
|
||||
|
||||
#else
|
||||
# define alloc_divert_blk(dev) (0)
|
||||
# define free_divert_blk(dev) do {} while (0)
|
||||
# define divert_ioctl(cmd, arg) (-ENOPKG)
|
||||
# define handle_diverter(skb) do {} while (0)
|
||||
#endif
|
||||
#endif
|
||||
#endif /* _LINUX_DIVERT_H */
|
@ -38,7 +38,6 @@
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
||||
struct divert_blk;
|
||||
struct vlan_group;
|
||||
struct ethtool_ops;
|
||||
struct netpoll_info;
|
||||
@ -517,11 +516,6 @@ struct net_device
|
||||
/* bridge stuff */
|
||||
struct net_bridge_port *br_port;
|
||||
|
||||
#ifdef CONFIG_NET_DIVERT
|
||||
/* this will get initialized at each interface type init routine */
|
||||
struct divert_blk *divert;
|
||||
#endif /* CONFIG_NET_DIVERT */
|
||||
|
||||
/* class/net/name entry */
|
||||
struct class_device class_dev;
|
||||
/* space for optional statistics and wireless sysfs groups */
|
||||
|
@ -72,8 +72,8 @@
|
||||
#define SIOCGIFTXQLEN 0x8942 /* Get the tx queue length */
|
||||
#define SIOCSIFTXQLEN 0x8943 /* Set the tx queue length */
|
||||
|
||||
#define SIOCGIFDIVERT 0x8944 /* Frame diversion support */
|
||||
#define SIOCSIFDIVERT 0x8945 /* Set frame diversion options */
|
||||
/* SIOCGIFDIVERT was: 0x8944 Frame diversion support */
|
||||
/* SIOCSIFDIVERT was: 0x8945 Set frame diversion options */
|
||||
|
||||
#define SIOCETHTOOL 0x8946 /* Ethtool interface */
|
||||
|
||||
|
27
net/Kconfig
27
net/Kconfig
@ -175,33 +175,6 @@ source "net/ipx/Kconfig"
|
||||
source "drivers/net/appletalk/Kconfig"
|
||||
source "net/x25/Kconfig"
|
||||
source "net/lapb/Kconfig"
|
||||
|
||||
config NET_DIVERT
|
||||
bool "Frame Diverter (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL && BROKEN
|
||||
---help---
|
||||
The Frame Diverter allows you to divert packets from the
|
||||
network, that are not aimed at the interface receiving it (in
|
||||
promisc. mode). Typically, a Linux box setup as an Ethernet bridge
|
||||
with the Frames Diverter on, can do some *really* transparent www
|
||||
caching using a Squid proxy for example.
|
||||
|
||||
This is very useful when you don't want to change your router's
|
||||
config (or if you simply don't have access to it).
|
||||
|
||||
The other possible usages of diverting Ethernet Frames are
|
||||
numberous:
|
||||
- reroute smtp traffic to another interface
|
||||
- traffic-shape certain network streams
|
||||
- transparently proxy smtp connections
|
||||
- etc...
|
||||
|
||||
For more informations, please refer to:
|
||||
<http://diverter.sourceforge.net/>
|
||||
<http://perso.wanadoo.fr/magpie/EtherDivert.html>
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
source "net/econet/Kconfig"
|
||||
source "net/wanrouter/Kconfig"
|
||||
source "net/sched/Kconfig"
|
||||
|
@ -12,7 +12,6 @@ obj-y += dev.o ethtool.o dev_mcast.o dst.o netevent.o \
|
||||
|
||||
obj-$(CONFIG_XFRM) += flow.o
|
||||
obj-$(CONFIG_SYSFS) += net-sysfs.o
|
||||
obj-$(CONFIG_NET_DIVERT) += dv.o
|
||||
obj-$(CONFIG_NET_PKTGEN) += pktgen.o
|
||||
obj-$(CONFIG_WIRELESS_EXT) += wireless.o
|
||||
obj-$(CONFIG_NETPOLL) += netpoll.o
|
||||
|
@ -98,7 +98,6 @@
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#include <linux/divert.h>
|
||||
#include <net/dst.h>
|
||||
#include <net/pkt_sched.h>
|
||||
#include <net/checksum.h>
|
||||
@ -1827,8 +1826,6 @@ int netif_receive_skb(struct sk_buff *skb)
|
||||
ncls:
|
||||
#endif
|
||||
|
||||
handle_diverter(skb);
|
||||
|
||||
if (handle_bridge(&skb, &pt_prev, &ret, orig_dev))
|
||||
goto out;
|
||||
|
||||
@ -2898,10 +2895,6 @@ int register_netdevice(struct net_device *dev)
|
||||
spin_lock_init(&dev->ingress_lock);
|
||||
#endif
|
||||
|
||||
ret = alloc_divert_blk(dev);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
dev->iflink = -1;
|
||||
|
||||
/* Init, if this function is available */
|
||||
@ -2910,13 +2903,13 @@ int register_netdevice(struct net_device *dev)
|
||||
if (ret) {
|
||||
if (ret > 0)
|
||||
ret = -EIO;
|
||||
goto out_err;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dev_valid_name(dev->name)) {
|
||||
ret = -EINVAL;
|
||||
goto out_err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev->ifindex = dev_new_index();
|
||||
@ -2930,7 +2923,7 @@ int register_netdevice(struct net_device *dev)
|
||||
= hlist_entry(p, struct net_device, name_hlist);
|
||||
if (!strncmp(d->name, dev->name, IFNAMSIZ)) {
|
||||
ret = -EEXIST;
|
||||
goto out_err;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2974,7 +2967,7 @@ int register_netdevice(struct net_device *dev)
|
||||
|
||||
ret = netdev_register_sysfs(dev);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
goto out;
|
||||
dev->reg_state = NETREG_REGISTERED;
|
||||
|
||||
/*
|
||||
@ -3001,9 +2994,6 @@ int register_netdevice(struct net_device *dev)
|
||||
|
||||
out:
|
||||
return ret;
|
||||
out_err:
|
||||
free_divert_blk(dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3320,8 +3310,6 @@ int unregister_netdevice(struct net_device *dev)
|
||||
/* Notifier chain MUST detach us from master device. */
|
||||
BUG_TRAP(!dev->master);
|
||||
|
||||
free_divert_blk(dev);
|
||||
|
||||
/* Finish processing unregister after unlock */
|
||||
net_set_todo(dev);
|
||||
|
||||
|
546
net/core/dv.c
546
net/core/dv.c
@ -1,546 +0,0 @@
|
||||
/*
|
||||
* INET An implementation of the TCP/IP protocol suite for the LINUX
|
||||
* operating system. INET is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* Generic frame diversion
|
||||
*
|
||||
* Authors:
|
||||
* Benoit LOCHER: initial integration within the kernel with support for ethernet
|
||||
* Dave Miller: improvement on the code (correctness, performance and source files)
|
||||
*
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/inet.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <net/dst.h>
|
||||
#include <net/arp.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/ip.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/checksum.h>
|
||||
#include <linux/divert.h>
|
||||
#include <linux/sockios.h>
|
||||
|
||||
const char sysctl_divert_version[32]="0.46"; /* Current version */
|
||||
|
||||
static int __init dv_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
module_init(dv_init);
|
||||
|
||||
/*
|
||||
* Allocate a divert_blk for a device. This must be an ethernet nic.
|
||||
*/
|
||||
int alloc_divert_blk(struct net_device *dev)
|
||||
{
|
||||
int alloc_size = (sizeof(struct divert_blk) + 3) & ~3;
|
||||
|
||||
dev->divert = NULL;
|
||||
if (dev->type == ARPHRD_ETHER) {
|
||||
dev->divert = kzalloc(alloc_size, GFP_KERNEL);
|
||||
if (dev->divert == NULL) {
|
||||
printk(KERN_INFO "divert: unable to allocate divert_blk for %s\n",
|
||||
dev->name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
dev_hold(dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a divert_blk allocated by the above function, if it was
|
||||
* allocated on that device.
|
||||
*/
|
||||
void free_divert_blk(struct net_device *dev)
|
||||
{
|
||||
if (dev->divert) {
|
||||
kfree(dev->divert);
|
||||
dev->divert=NULL;
|
||||
dev_put(dev);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds a tcp/udp (source or dest) port to an array
|
||||
*/
|
||||
static int add_port(u16 ports[], u16 port)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (port == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Storing directly in network format for performance,
|
||||
* thanks Dave :)
|
||||
*/
|
||||
port = htons(port);
|
||||
|
||||
for (i = 0; i < MAX_DIVERT_PORTS; i++) {
|
||||
if (ports[i] == port)
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_DIVERT_PORTS; i++) {
|
||||
if (ports[i] == 0) {
|
||||
ports[i] = port;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes a port from an array tcp/udp (source or dest)
|
||||
*/
|
||||
static int remove_port(u16 ports[], u16 port)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (port == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Storing directly in network format for performance,
|
||||
* thanks Dave !
|
||||
*/
|
||||
port = htons(port);
|
||||
|
||||
for (i = 0; i < MAX_DIVERT_PORTS; i++) {
|
||||
if (ports[i] == port) {
|
||||
ports[i] = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Some basic sanity checks on the arguments passed to divert_ioctl() */
|
||||
static int check_args(struct divert_cf *div_cf, struct net_device **dev)
|
||||
{
|
||||
char devname[32];
|
||||
int ret;
|
||||
|
||||
if (dev == NULL)
|
||||
return -EFAULT;
|
||||
|
||||
/* GETVERSION: all other args are unused */
|
||||
if (div_cf->cmd == DIVCMD_GETVERSION)
|
||||
return 0;
|
||||
|
||||
/* Network device index should reasonably be between 0 and 1000 :) */
|
||||
if (div_cf->dev_index < 0 || div_cf->dev_index > 1000)
|
||||
return -EINVAL;
|
||||
|
||||
/* Let's try to find the ifname */
|
||||
sprintf(devname, "eth%d", div_cf->dev_index);
|
||||
*dev = dev_get_by_name(devname);
|
||||
|
||||
/* dev should NOT be null */
|
||||
if (*dev == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
ret = 0;
|
||||
|
||||
/* user issuing the ioctl must be a super one :) */
|
||||
if (!capable(CAP_SYS_ADMIN)) {
|
||||
ret = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Device must have a divert_blk member NOT null */
|
||||
if ((*dev)->divert == NULL)
|
||||
ret = -EINVAL;
|
||||
out:
|
||||
dev_put(*dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* control function of the diverter
|
||||
*/
|
||||
#if 0
|
||||
#define DVDBG(a) \
|
||||
printk(KERN_DEBUG "divert_ioctl() line %d %s\n", __LINE__, (a))
|
||||
#else
|
||||
#define DVDBG(a)
|
||||
#endif
|
||||
|
||||
int divert_ioctl(unsigned int cmd, struct divert_cf __user *arg)
|
||||
{
|
||||
struct divert_cf div_cf;
|
||||
struct divert_blk *div_blk;
|
||||
struct net_device *dev;
|
||||
int ret;
|
||||
|
||||
switch (cmd) {
|
||||
case SIOCGIFDIVERT:
|
||||
DVDBG("SIOCGIFDIVERT, copy_from_user");
|
||||
if (copy_from_user(&div_cf, arg, sizeof(struct divert_cf)))
|
||||
return -EFAULT;
|
||||
DVDBG("before check_args");
|
||||
ret = check_args(&div_cf, &dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
DVDBG("after checkargs");
|
||||
div_blk = dev->divert;
|
||||
|
||||
DVDBG("befre switch()");
|
||||
switch (div_cf.cmd) {
|
||||
case DIVCMD_GETSTATUS:
|
||||
/* Now, just give the user the raw divert block
|
||||
* for him to play with :)
|
||||
*/
|
||||
if (copy_to_user(div_cf.arg1.ptr, dev->divert,
|
||||
sizeof(struct divert_blk)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
|
||||
case DIVCMD_GETVERSION:
|
||||
DVDBG("GETVERSION: checking ptr");
|
||||
if (div_cf.arg1.ptr == NULL)
|
||||
return -EINVAL;
|
||||
DVDBG("GETVERSION: copying data to userland");
|
||||
if (copy_to_user(div_cf.arg1.ptr,
|
||||
sysctl_divert_version, 32))
|
||||
return -EFAULT;
|
||||
DVDBG("GETVERSION: data copied");
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SIOCSIFDIVERT:
|
||||
if (copy_from_user(&div_cf, arg, sizeof(struct divert_cf)))
|
||||
return -EFAULT;
|
||||
|
||||
ret = check_args(&div_cf, &dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
div_blk = dev->divert;
|
||||
|
||||
switch(div_cf.cmd) {
|
||||
case DIVCMD_RESET:
|
||||
div_blk->divert = 0;
|
||||
div_blk->protos = DIVERT_PROTO_NONE;
|
||||
memset(div_blk->tcp_dst, 0,
|
||||
MAX_DIVERT_PORTS * sizeof(u16));
|
||||
memset(div_blk->tcp_src, 0,
|
||||
MAX_DIVERT_PORTS * sizeof(u16));
|
||||
memset(div_blk->udp_dst, 0,
|
||||
MAX_DIVERT_PORTS * sizeof(u16));
|
||||
memset(div_blk->udp_src, 0,
|
||||
MAX_DIVERT_PORTS * sizeof(u16));
|
||||
return 0;
|
||||
|
||||
case DIVCMD_DIVERT:
|
||||
switch(div_cf.arg1.int32) {
|
||||
case DIVARG1_ENABLE:
|
||||
if (div_blk->divert)
|
||||
return -EALREADY;
|
||||
div_blk->divert = 1;
|
||||
break;
|
||||
|
||||
case DIVARG1_DISABLE:
|
||||
if (!div_blk->divert)
|
||||
return -EALREADY;
|
||||
div_blk->divert = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DIVCMD_IP:
|
||||
switch(div_cf.arg1.int32) {
|
||||
case DIVARG1_ENABLE:
|
||||
if (div_blk->protos & DIVERT_PROTO_IP)
|
||||
return -EALREADY;
|
||||
div_blk->protos |= DIVERT_PROTO_IP;
|
||||
break;
|
||||
|
||||
case DIVARG1_DISABLE:
|
||||
if (!(div_blk->protos & DIVERT_PROTO_IP))
|
||||
return -EALREADY;
|
||||
div_blk->protos &= ~DIVERT_PROTO_IP;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DIVCMD_TCP:
|
||||
switch(div_cf.arg1.int32) {
|
||||
case DIVARG1_ENABLE:
|
||||
if (div_blk->protos & DIVERT_PROTO_TCP)
|
||||
return -EALREADY;
|
||||
div_blk->protos |= DIVERT_PROTO_TCP;
|
||||
break;
|
||||
|
||||
case DIVARG1_DISABLE:
|
||||
if (!(div_blk->protos & DIVERT_PROTO_TCP))
|
||||
return -EALREADY;
|
||||
div_blk->protos &= ~DIVERT_PROTO_TCP;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DIVCMD_TCPDST:
|
||||
switch(div_cf.arg1.int32) {
|
||||
case DIVARG1_ADD:
|
||||
return add_port(div_blk->tcp_dst,
|
||||
div_cf.arg2.uint16);
|
||||
|
||||
case DIVARG1_REMOVE:
|
||||
return remove_port(div_blk->tcp_dst,
|
||||
div_cf.arg2.uint16);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DIVCMD_TCPSRC:
|
||||
switch(div_cf.arg1.int32) {
|
||||
case DIVARG1_ADD:
|
||||
return add_port(div_blk->tcp_src,
|
||||
div_cf.arg2.uint16);
|
||||
|
||||
case DIVARG1_REMOVE:
|
||||
return remove_port(div_blk->tcp_src,
|
||||
div_cf.arg2.uint16);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DIVCMD_UDP:
|
||||
switch(div_cf.arg1.int32) {
|
||||
case DIVARG1_ENABLE:
|
||||
if (div_blk->protos & DIVERT_PROTO_UDP)
|
||||
return -EALREADY;
|
||||
div_blk->protos |= DIVERT_PROTO_UDP;
|
||||
break;
|
||||
|
||||
case DIVARG1_DISABLE:
|
||||
if (!(div_blk->protos & DIVERT_PROTO_UDP))
|
||||
return -EALREADY;
|
||||
div_blk->protos &= ~DIVERT_PROTO_UDP;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DIVCMD_UDPDST:
|
||||
switch(div_cf.arg1.int32) {
|
||||
case DIVARG1_ADD:
|
||||
return add_port(div_blk->udp_dst,
|
||||
div_cf.arg2.uint16);
|
||||
|
||||
case DIVARG1_REMOVE:
|
||||
return remove_port(div_blk->udp_dst,
|
||||
div_cf.arg2.uint16);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DIVCMD_UDPSRC:
|
||||
switch(div_cf.arg1.int32) {
|
||||
case DIVARG1_ADD:
|
||||
return add_port(div_blk->udp_src,
|
||||
div_cf.arg2.uint16);
|
||||
|
||||
case DIVARG1_REMOVE:
|
||||
return remove_port(div_blk->udp_src,
|
||||
div_cf.arg2.uint16);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DIVCMD_ICMP:
|
||||
switch(div_cf.arg1.int32) {
|
||||
case DIVARG1_ENABLE:
|
||||
if (div_blk->protos & DIVERT_PROTO_ICMP)
|
||||
return -EALREADY;
|
||||
div_blk->protos |= DIVERT_PROTO_ICMP;
|
||||
break;
|
||||
|
||||
case DIVARG1_DISABLE:
|
||||
if (!(div_blk->protos & DIVERT_PROTO_ICMP))
|
||||
return -EALREADY;
|
||||
div_blk->protos &= ~DIVERT_PROTO_ICMP;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check if packet should have its dest mac address set to the box itself
|
||||
* for diversion
|
||||
*/
|
||||
|
||||
#define ETH_DIVERT_FRAME(skb) \
|
||||
memcpy(eth_hdr(skb), skb->dev->dev_addr, ETH_ALEN); \
|
||||
skb->pkt_type=PACKET_HOST
|
||||
|
||||
void divert_frame(struct sk_buff *skb)
|
||||
{
|
||||
struct ethhdr *eth = eth_hdr(skb);
|
||||
struct iphdr *iph;
|
||||
struct tcphdr *tcph;
|
||||
struct udphdr *udph;
|
||||
struct divert_blk *divert = skb->dev->divert;
|
||||
int i, src, dst;
|
||||
unsigned char *skb_data_end = skb->data + skb->len;
|
||||
|
||||
/* Packet is already aimed at us, return */
|
||||
if (!compare_ether_addr(eth->h_dest, skb->dev->dev_addr))
|
||||
return;
|
||||
|
||||
/* proto is not IP, do nothing */
|
||||
if (eth->h_proto != htons(ETH_P_IP))
|
||||
return;
|
||||
|
||||
/* Divert all IP frames ? */
|
||||
if (divert->protos & DIVERT_PROTO_IP) {
|
||||
ETH_DIVERT_FRAME(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check for possible (maliciously) malformed IP frame (thanks Dave) */
|
||||
iph = (struct iphdr *) skb->data;
|
||||
if (((iph->ihl<<2)+(unsigned char*)(iph)) >= skb_data_end) {
|
||||
printk(KERN_INFO "divert: malformed IP packet !\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (iph->protocol) {
|
||||
/* Divert all ICMP frames ? */
|
||||
case IPPROTO_ICMP:
|
||||
if (divert->protos & DIVERT_PROTO_ICMP) {
|
||||
ETH_DIVERT_FRAME(skb);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Divert all TCP frames ? */
|
||||
case IPPROTO_TCP:
|
||||
if (divert->protos & DIVERT_PROTO_TCP) {
|
||||
ETH_DIVERT_FRAME(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check for possible (maliciously) malformed IP
|
||||
* frame (thanx Dave)
|
||||
*/
|
||||
tcph = (struct tcphdr *)
|
||||
(((unsigned char *)iph) + (iph->ihl<<2));
|
||||
if (((unsigned char *)(tcph+1)) >= skb_data_end) {
|
||||
printk(KERN_INFO "divert: malformed TCP packet !\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Divert some tcp dst/src ports only ?*/
|
||||
for (i = 0; i < MAX_DIVERT_PORTS; i++) {
|
||||
dst = divert->tcp_dst[i];
|
||||
src = divert->tcp_src[i];
|
||||
if ((dst && dst == tcph->dest) ||
|
||||
(src && src == tcph->source)) {
|
||||
ETH_DIVERT_FRAME(skb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* Divert all UDP frames ? */
|
||||
case IPPROTO_UDP:
|
||||
if (divert->protos & DIVERT_PROTO_UDP) {
|
||||
ETH_DIVERT_FRAME(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check for possible (maliciously) malformed IP
|
||||
* packet (thanks Dave)
|
||||
*/
|
||||
udph = (struct udphdr *)
|
||||
(((unsigned char *)iph) + (iph->ihl<<2));
|
||||
if (((unsigned char *)(udph+1)) >= skb_data_end) {
|
||||
printk(KERN_INFO
|
||||
"divert: malformed UDP packet !\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Divert some udp dst/src ports only ? */
|
||||
for (i = 0; i < MAX_DIVERT_PORTS; i++) {
|
||||
dst = divert->udp_dst[i];
|
||||
src = divert->udp_src[i];
|
||||
if ((dst && dst == udph->dest) ||
|
||||
(src && src == udph->source)) {
|
||||
ETH_DIVERT_FRAME(skb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
@ -21,10 +21,6 @@ extern __u32 sysctl_rmem_max;
|
||||
|
||||
extern int sysctl_core_destroy_delay;
|
||||
|
||||
#ifdef CONFIG_NET_DIVERT
|
||||
extern char sysctl_divert_version[];
|
||||
#endif /* CONFIG_NET_DIVERT */
|
||||
|
||||
#ifdef CONFIG_XFRM
|
||||
extern u32 sysctl_xfrm_aevent_etime;
|
||||
extern u32 sysctl_xfrm_aevent_rseqth;
|
||||
@ -105,16 +101,6 @@ ctl_table core_table[] = {
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec
|
||||
},
|
||||
#ifdef CONFIG_NET_DIVERT
|
||||
{
|
||||
.ctl_name = NET_CORE_DIVERT_VERSION,
|
||||
.procname = "divert_version",
|
||||
.data = (void *)sysctl_divert_version,
|
||||
.maxlen = 32,
|
||||
.mode = 0444,
|
||||
.proc_handler = &proc_dostring
|
||||
},
|
||||
#endif /* CONFIG_NET_DIVERT */
|
||||
#ifdef CONFIG_XFRM
|
||||
{
|
||||
.ctl_name = NET_CORE_AEVENT_ETIME,
|
||||
|
@ -77,7 +77,6 @@
|
||||
#include <linux/cache.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/divert.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/syscalls.h>
|
||||
@ -852,11 +851,6 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
||||
err = vlan_ioctl_hook(argp);
|
||||
mutex_unlock(&vlan_ioctl_mutex);
|
||||
break;
|
||||
case SIOCGIFDIVERT:
|
||||
case SIOCSIFDIVERT:
|
||||
/* Convert this to call through a hook */
|
||||
err = divert_ioctl(cmd, argp);
|
||||
break;
|
||||
case SIOCADDDLCI:
|
||||
case SIOCDELDLCI:
|
||||
err = -ENOPKG;
|
||||
|
Loading…
Reference in New Issue
Block a user