Re: [PATCH] Runtime interception method switch

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sun, Jan 13, 2008 at 04:12:38PM +0100, Raphael Vallazza wrote:
> Hi,
>
> i've just finished the patch for changing the connection interception  
> method at runtime (in /proc/sys/net/ipv4/vs/input_hook), it works pretty 
> well :) I've tested it with all the seetings and it worked without any 
> problems.
>
> It has been made for net-2.6.25 branch. I've also made some minor  
> corrections to the "connection interception choice patch". These patches 
> have to be appliet together...
>
> Thanks,
> Raphael
>
> P.S. i hope my mailer doesn't mess up the patches this time :-/

Unfortunately it did :-(

That asside, the patches look basically good.
I rediffed them and they seem to work fine.
Let me know if you want my version of the patches,
though I have not fixed all the issues that I saw.

Comments in-line.

> -- 
> :: e n d i a n
> :: open source - open minds
>
>
> #### 0001-IPVS-Add-choice-for-connection-interception-method.patch ####
>
> [PATCH] [IPVS]: Add choice for connection interception method
>
> This patch adds an option to set the position at which IPVS intercepts
> incoming connections from Netfilter.
>
> The options are:
>
> 1. INPUT (default)
> Intercept incoming connections after they have traveled through
> the INPUT table, only connections that have the director as
> destination address will be processed.
>
> 2. FORWARD
> Intercept incoming connections after they have traveled through
> the INPUT or the FORWARD table. It has the same functionlity of
> the "INPUT method", but also processes connections that are
> routed through the director, supporting VIP-less setups.
>
> 3. PREROUTING
> Intercept incoming connections before DNAT and input filtering
> has been applied, this enables transparent proxying on realnodes
> and localnode.
>
> Signed-off-by: Raphael Vallazza <raphael@xxxxxxxxxx>
> ---
>  net/ipv4/ipvs/Kconfig      |   44 +++++++++++++++++++++++++++++++++++ 
> +++++++++
>  net/ipv4/ipvs/ip_vs_core.c |   30 +++++++++++++++++++++++++++++-
>  2 files changed, 73 insertions(+), 1 deletions(-)
>
> diff --git a/net/ipv4/ipvs/Kconfig b/net/ipv4/ipvs/Kconfig
> index 09d0c3f..319f3e8 100644
> --- a/net/ipv4/ipvs/Kconfig
> +++ b/net/ipv4/ipvs/Kconfig
> @@ -24,6 +24,50 @@ menuconfig IP_VS
>
>  if IP_VS
>
> +choice
> +	prompt "IPVS connection interception method"
> +	default IP_VS_INPUT_LOCAL_IN
> +	help
> +	  This option sets the position at which IPVS intercepts incoming
> +	  connections from Netfilter. If in doubt select 'LOCAL_IN'.
> +
> +config IP_VS_INPUT_LOCAL_IN
> +	bool "INPUT"
> +	---help---
> +	  Intercept incoming connections after they have traveled through
> +	  the INPUT table, only connections that have the director as
> +	  destination address will be processed.
> +
> +	  This method allows to apply packet filtering in the INPUT table
> +	  before the connection is intercepted by IPVS.
> +
> +config IP_VS_INPUT_FORWARD
> +	bool "FORWARD"
> +	---help---
> +	  Intercept incoming connections after they have traveled through
> +	  the INPUT or the FORWARD table. It has the same functionlity of
> +	  the "INPUT method", but also processes connections that are
> +	  routed through the director, supporting VIP-less setups.
> +
> +	  This method allows to apply packet filtering in the INPUT or
> +	  FORWARD table, before the connection is intercepted by IPVS.
> +
> +config IP_VS_INPUT_PRE_ROUTING
> +	bool "PREROUTING"
> +	---help---
> +	  Intercept incoming connections before DNAT and input filtering
> +	  has been applied, this allows transparent proxying on realnodes
> +	  and localnode. Incoming connections are intercepted right after
> +	  the mangle PREROUTING table and before the nat PREROUTING table,
> +	  supporting VIP-less setups.
> +
> +	  WARNING: This method doesn't apply any packet filtering before
> +	  packets are intercepted by IPVS. To filter the connections that
> +	  should be intercepted, you have to mark the traffic in the
> +	  mangle PREROUTING table.
> +
> +endchoice
> +
>  config	IP_VS_DEBUG
>  	bool "IP virtual server debugging"
>  	---help---
> diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
> index 963981a..0da4ef6 100644
> --- a/net/ipv4/ipvs/ip_vs_core.c
> +++ b/net/ipv4/ipvs/ip_vs_core.c
> @@ -1026,6 +1026,7 @@ ip_vs_forward_icmp(unsigned int hooknum, struct  
> sk_buff *skb,
>
>
>  static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
> +#if defined(CONFIG_IP_VS_INPUT_LOCAL_IN) || defined(CONFIG_IP_VS_INPUT_FORWARD)

Shouldn't this just be

#if defined(CONFIG_IP_VS_INPUT_LOCAL_IN)

>  	/* After packet filtering, forward packet through VS/DR, VS/TUN,
>  	 * or VS/NAT(change destination), so that filtering rules can be
>  	 * applied to IPVS. */
> @@ -1036,6 +1037,33 @@ static struct nf_hook_ops ip_vs_ops[]  
> __read_mostly = {
>  		.hooknum        = NF_INET_LOCAL_IN,
>  		.priority       = 100,
>  	},
> +#endif
> +#ifdef CONFIG_IP_VS_INPUT_FORWARD
> +	/* Intercept incoming connections after they have traveled through
> +	 * the INPUT or the FORWARD table. It has the same functionlity of
> +	 * the "INPUT method", but also processes connections that are
> +	 * routed through the director, supporting VIP-less setups. */
> +	{
> +		.hook		= ip_vs_in,
> +		.owner		= THIS_MODULE,
> +		.pf		= PF_INET,
> +		.hooknum        = NF_INET_FORWARD,
> +		.priority       = 98,
> +	},
> +#endif
> +#ifdef CONFIG_IP_VS_INPUT_PRE_ROUTING
> +	/* Intercept incoming connections before DNAT and input filtering
> +	 * has been applied, this enables ransparent proxying on realnodes
> +	 * and localnode. Hook right after MANGLE and before NAT_DST.
> +	 */
> +	{
> +		.hook           = ip_vs_in,
> +		.owner          = THIS_MODULE,
> +		.pf             = PF_INET,
> +		.hooknum        = NF_INET_PRE_ROUTING,
> +		.priority       = NF_IP_PRI_NAT_DST - 1,
> +	},
> +#endif
>  	/* After packet filtering, change source only for VS/NAT */
>  	{
>  		.hook		= ip_vs_out,
> @@ -1059,7 +1087,7 @@ static struct nf_hook_ops ip_vs_ops[]  
> __read_mostly = {
>  		.owner		= THIS_MODULE,
>  		.pf		= PF_INET,
>  		.hooknum        = NF_INET_POST_ROUTING,
> -		.priority       = NF_IP_PRI_NAT_SRC-1,
> +		.priority       = NF_IP_PRI_NAT_SRC - 1,
>  	},
>  };
>
> -- 
> 1.5.3.7
>
>
> #### 0002-IPVS-Runtime-interception-method-switch.patch ####
>
> [IPVS]: Runtime interception method switch
>
> This patch allows to switch interception method at runtime by changing
> the value of /proc/sys/net/ipv4/vs/input_hook with one of the following
> values:
> 0 = INPUT
> 1 = FORWARD
> 2 = PREROUTING

Could you ass documentation of this to
Documentation/networking/ipvs-sysctl.txt ?

>
> Signed-off-by: Raphael Vallazza <raphael@xxxxxxxxxx>
> ---
>  include/net/ip_vs.h        |   15 +++++
>  net/ipv4/ipvs/Kconfig      |   10 +++-
>  net/ipv4/ipvs/ip_vs_core.c |  141 +++++++++++++++++++++++++++++++++++ 
> ++-------
>  net/ipv4/ipvs/ip_vs_ctl.c  |   43 +++++++++++++
>  4 files changed, 186 insertions(+), 23 deletions(-)
>
> diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
> index 56f3c94..6b71e31 100644
> --- a/include/net/ip_vs.h
> +++ b/include/net/ip_vs.h
> @@ -681,6 +681,21 @@ extern void ip_vs_init_hash_table(struct list_head 
> *table, int rows);
>  #define IP_VS_APP_TYPE_FTP	1
>
>  /*
> + *	IPVS input hook functions
> + */
> +enum {
> +	IP_VS_INPUT_HOOK_FIRST = -1,
> +	IP_VS_INPUT_HOOK_LOCAL_IN,
> +	IP_VS_INPUT_HOOK_FORWARD,
> +	IP_VS_INPUT_HOOK_PRE_ROUTING,
> +	IP_VS_INPUT_HOOK_LAST,
> +};
> +
> +extern int ip_vs_get_input_hook(void);
> +extern int ip_vs_register_hooks(int input_hook);
> +extern int ip_vs_unregister_hooks(int input_hook);
> +
> +/*
>   *     ip_vs_conn handling functions
>   *     (from ip_vs_conn.c)
>   */
> diff --git a/net/ipv4/ipvs/Kconfig b/net/ipv4/ipvs/Kconfig
> index 319f3e8..19217d7 100644
> --- a/net/ipv4/ipvs/Kconfig
> +++ b/net/ipv4/ipvs/Kconfig
> @@ -28,8 +28,14 @@ choice
>  	prompt "IPVS connection interception method"
>  	default IP_VS_INPUT_LOCAL_IN
>  	help
> -	  This option sets the position at which IPVS intercepts incoming
> -	  connections from Netfilter. If in doubt select 'LOCAL_IN'.
> +	  This option selects the default position at which IPVS intercepts
> +	  incoming connections from Netfilter. If in doubt select 'INPUT'.
> +	
> +	  The interception method can be switched at runtime in
> +	  /proc/sys/net/ipv4/vs/input_hook with the following values:
> +	    0 = INPUT
> +	    1 = FORWARD
> +	    2 = PREROUTING	
>
>  config IP_VS_INPUT_LOCAL_IN
>  	bool "INPUT"
> diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
> index 0da4ef6..6acfbbd 100644
> --- a/net/ipv4/ipvs/ip_vs_core.c
> +++ b/net/ipv4/ipvs/ip_vs_core.c
> @@ -1024,12 +1024,111 @@ ip_vs_forward_icmp(unsigned int hooknum, struct 
> sk_buff *skb,
>  	return ip_vs_in_icmp(skb, &r, hooknum);
>  }
>
> +/*
> + * Register netfilter hook based on input_hook type
> + */
> +
> +int ip_vs_register_hooks(int input_hook)
> +{
> +	int ret;
> +	char *hookstr;
> +	struct nf_hook_ops *in_hooks;

	Just me, but in_hook seems like a better name than in_hooks.

> +	int count;
> +
> +	IP_VS_DBG(5, "Registering input hooks: %i\n", input_hook);
> +
> +	switch (input_hook) {
> +	case IP_VS_INPUT_HOOK_LOCAL_IN:
> +		hookstr = "INPUT";
> +		in_hooks = ip_vs_ops_local_in;
> +		count = ARRAY_SIZE(ip_vs_ops_local_in);
> +		break;
> +	case IP_VS_INPUT_HOOK_FORWARD:
> +		hookstr = "FORWARD";
> +		in_hooks = ip_vs_ops_forward;
> +		count = ARRAY_SIZE(ip_vs_ops_forward);
> +		break;
> +	case IP_VS_INPUT_HOOK_PRE_ROUTING:
> +		hookstr = "PREROUTING";
> +		in_hooks = ip_vs_ops_pre_routing;
> +		count = ARRAY_SIZE(ip_vs_ops_pre_routing);
> +		break;
> +	default:
> +		return -1;
> +	}

Could the calculation of count be moved out of the switch to here
as the following?

	count = ARRAY_SIZE(in_hooks);
> +
> +	ret = nf_register_hooks(in_hooks, count);
> +	if (ret < 0) {
> +		IP_VS_ERR("Can't register %s hooks.\n", hookstr);
> +		return -1;
> +	}
> +
> +	ret = nf_register_hooks(ip_vs_ops_generic,
> +				ARRAY_SIZE(ip_vs_ops_generic));
> +	if (ret < 0) {
> +		nf_unregister_hooks(in_hooks, count);
> +		IP_VS_ERR("Can't register generic hooks.\n");
> +		return -1;
> +	}
> +
> +	IP_VS_INFO("Registered interception method: %s\n", hookstr);
> +	return 0;
> +}
> +
> +/*
> + * Unregister netfilter hook based on input_hook type
> + */
>
> -static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
> -#if defined(CONFIG_IP_VS_INPUT_LOCAL_IN) ||  
> defined(CONFIG_IP_VS_INPUT_FORWARD)
> -	/* After packet filtering, forward packet through VS/DR, VS/TUN,
> -	 * or VS/NAT(change destination), so that filtering rules can be
> -	 * applied to IPVS. */
> +int ip_vs_unregister_hooks(int input_hook)
> +{
> +	struct nf_hook_ops *in_hooks;
> +	int count;
> +
> +	IP_VS_DBG(5, "Unregistering input hooks: %i\n", input_hook);
> +
> +	switch (input_hook) {
> +	case IP_VS_INPUT_HOOK_LOCAL_IN:
> +		in_hooks = ip_vs_ops_local_in;
> +		count = ARRAY_SIZE(ip_vs_ops_local_in);
> +		break;
> +	case IP_VS_INPUT_HOOK_FORWARD:
> +		in_hooks = ip_vs_ops_forward;
> +		count = ARRAY_SIZE(ip_vs_ops_forward);
> +		break;
> +	case IP_VS_INPUT_HOOK_PRE_ROUTING:
> +		in_hooks = ip_vs_ops_pre_routing;
> +		count = ARRAY_SIZE(ip_vs_ops_pre_routing);
> +		break;
> +	default:
> +		return -1;
> +	}

Again, could the calculation of count be moved out of the switch
statement? Perhaps it could just be put directly in the
call to nf_unregister_hooks() ?

	nf_unregister_hooks(in_hooks, ARRAY_SIZE(in_hooks));

> +
> +	nf_unregister_hooks(in_hooks, count);
> +	nf_unregister_hooks(ip_vs_ops_generic, ARRAY_SIZE(ip_vs_ops_generic));
> +
> +	IP_VS_DBG(5, "Unregistered input hooks.\n");
> +	return 0;
> +}

I found that I needed to move the definition of ip_ve_register_hooks()
and ip_vs_unregister_hooks() to below the definition of all
the struct nf_hook_ops, as they are used in these functions.

The hunks below seem a bit messed up
and ip_vs_ips_pre_forward ends up with a duplicate
of the NF_INET_LOCAL_IN fragment from ip_vs_ops_local_in.

> +
> +
> +/* After packet filtering, forward packet through VS/DR, VS/TUN,
> + * or VS/NAT(change destination), so that filtering rules can be
> + * applied to IPVS. */
> +static struct nf_hook_ops ip_vs_ops_local_in[] __read_mostly = {
> +	{
> +		.hook		= ip_vs_in,
> +		.owner		= THIS_MODULE,
> +		.pf		= PF_INET,
> +		.hooknum        = NF_INET_LOCAL_IN,
> +		.priority       = 100,
> +	},
> +};
> +
> +/* Intercept incoming connections after they have traveled through
> + * the INPUT or the FORWARD table. It has the same functionlity of
> + * the "INPUT method", but also processes connections that are
> + * routed through the director, supporting VIP-less setups. */
> +static struct nf_hook_ops ip_vs_ops_forward[] __read_mostly = {
>  	{
>  		.hook		= ip_vs_in,
>  		.owner		= THIS_MODULE,
> @@ -1037,12 +1136,6 @@ static struct nf_hook_ops ip_vs_ops[]  
> __read_mostly = {
>  		.hooknum        = NF_INET_LOCAL_IN,
>  		.priority       = 100,
>  	},
> -#endif
> -#ifdef CONFIG_IP_VS_INPUT_FORWARD
> -	/* Intercept incoming connections after they have traveled through
> -	 * the INPUT or the FORWARD table. It has the same functionlity of
> -	 * the "INPUT method", but also processes connections that are
> -	 * routed through the director, supporting VIP-less setups. */
>  	{
>  		.hook		= ip_vs_in,
>  		.owner		= THIS_MODULE,
> @@ -1050,12 +1143,13 @@ static struct nf_hook_ops ip_vs_ops[]  
> __read_mostly = {
>  		.hooknum        = NF_INET_FORWARD,
>  		.priority       = 98,
>  	},
> -#endif
> -#ifdef CONFIG_IP_VS_INPUT_PRE_ROUTING
> -	/* Intercept incoming connections before DNAT and input filtering
> -	 * has been applied, this enables ransparent proxying on realnodes
> -	 * and localnode. Hook right after MANGLE and before NAT_DST.
> -	 */
> +};
> +
> +/* Intercept incoming connections before DNAT and input filtering
> + * has been applied, this enables ransparent proxying on realnodes
> + * and localnode. Hook right after MANGLE and before NAT_DST.
> + */
> +static struct nf_hook_ops ip_vs_ops_pre_routing[] __read_mostly = {
>  	{
>  		.hook           = ip_vs_in,
>  		.owner          = THIS_MODULE,
> @@ -1063,7 +1157,13 @@ static struct nf_hook_ops ip_vs_ops[]  
> __read_mostly = {
>  		.hooknum        = NF_INET_PRE_ROUTING,
>  		.priority       = NF_IP_PRI_NAT_DST - 1,
>  	},
> -#endif
> +};
> +
> +/*
> + * Generic Netfilter hooks required for all the input methods
> + */
> +
> +static struct nf_hook_ops ip_vs_ops_generic[] __read_mostly = {
>  	/* After packet filtering, change source only for VS/NAT */
>  	{
>  		.hook		= ip_vs_out,
> @@ -1119,9 +1219,8 @@ static int __init ip_vs_init(void)
>  		goto cleanup_app;
>  	}
>
> -	ret = nf_register_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
> +	ret = ip_vs_register_hooks(ip_vs_get_input_hook());
>  	if (ret < 0) {
> -		IP_VS_ERR("can't register hooks.\n");
>  		goto cleanup_conn;
>  	}
>
> @@ -1141,7 +1240,7 @@ static int __init ip_vs_init(void)
>
>  static void __exit ip_vs_cleanup(void)
>  {
> -	nf_unregister_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
> +	ip_vs_unregister_hooks(ip_vs_get_input_hook());
>  	ip_vs_conn_cleanup();
>  	ip_vs_app_cleanup();
>  	ip_vs_protocol_cleanup();
> diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
> index 94c5767..1e05c54 100644
> --- a/net/ipv4/ipvs/ip_vs_ctl.c
> +++ b/net/ipv4/ipvs/ip_vs_ctl.c
> @@ -82,6 +82,15 @@ int sysctl_ip_vs_expire_quiescent_template = 0;
>  int sysctl_ip_vs_sync_threshold[2] = { 3, 50 };
>  int sysctl_ip_vs_nat_icmp_send = 0;
>
> +#ifdef CONFIG_IP_VS_INPUT_LOCAL_IN
> +static int sysctl_ip_vs_input_hook = IP_VS_INPUT_HOOK_LOCAL_IN;
> +#endif
> +#ifdef CONFIG_IP_VS_INPUT_FORWARD
> +static int sysctl_ip_vs_input_hook = IP_VS_INPUT_HOOK_FORWARD;
> +#endif
> +#ifdef CONFIG_IP_VS_INPUT_PRE_ROUTING
> +static int sysctl_ip_vs_input_hook = IP_VS_INPUT_HOOK_PRE_ROUTING;
> +#endif
>
>  #ifdef CONFIG_IP_VS_DEBUG
>  static int sysctl_ip_vs_debug_level = 0;
> @@ -92,6 +101,11 @@ int ip_vs_get_debug_level(void)
>  }
>  #endif
>
> +int ip_vs_get_input_hook(void)
> +{
> +	return sysctl_ip_vs_input_hook;
> +}
> +
>  /*
>   *	update_defense_level is called from keventd and from sysctl,
>   *	so it needs to protect itself from softirqs
> @@ -1376,6 +1390,28 @@ static int ip_vs_zero_all(void)
>  	return 0;
>  }
>
> +static int
> +proc_do_input_hook(struct ctl_table *table, int write, struct file  
> *filp,
> +		   void __user *buffer, size_t *lenp, loff_t *ppos)
> +{
> +	char *valp = table->data;
> +	int oldval = *valp;
> +	int rc;
> +
> +	rc = proc_dointvec(table, write, filp, buffer, lenp, ppos);
> +	if (write && (*valp != oldval)) {
> +		if ((*valp <= IP_VS_INPUT_HOOK_FIRST) ||
> +		    (*valp >= IP_VS_INPUT_HOOK_LAST)) {
> +			IP_VS_ERR("Invalid input hook value: %i\n", *valp);
> +			*valp = oldval;
> +		} else {
> +			/* unregister old and register new input hooks */
> +			ip_vs_unregister_hooks(oldval);
> +			ip_vs_register_hooks(*valp);
> +		}
> +	}
> +	return rc;
> +}
>
>  static int
>  proc_do_defense_mode(ctl_table *table, int write, struct file * filp,
> @@ -1430,6 +1466,13 @@ static struct ctl_table vs_vars[] = {
>  		.mode		= 0644,
>  		.proc_handler	= &proc_dointvec,
>  	},
> +	{
> +		.procname	= "input_hook",
> +		.data		= &sysctl_ip_vs_input_hook,
> +		.maxlen		= sizeof(int),
> +		.mode		= 0644,
> +		.proc_handler	= &proc_do_input_hook,
> +	},
>  #ifdef CONFIG_IP_VS_DEBUG
>  	{
>  		.procname	= "debug_level",
> -- 
> 1.5.3.7
>
>
>
> -
> To unsubscribe from this list: send the line "unsubscribe lvs-devel" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
Horms

-
To unsubscribe from this list: send the line "unsubscribe lvs-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Filesystem Devel]     [Linux NFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]     [X.Org]

  Powered by Linux