Re: [PATCH v3] netfilter: introduce l2tp match extension

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

 



Hi James,

More comments, firstly, a minor glitch: git am complains about one
whitespace.

patch:66:
new blank line at EOF.
+
warning: 1 line adds whitespace errors

On Tue, Nov 26, 2013 at 04:40:09PM +0000, James Chapman wrote:
> Introduce an xtables add-on for matching L2TP packets. Supports L2TPv2
> and L2TPv3 over IPv4 and IPv6. As well as filtering on L2TP tunnel-id
> and session-id, the filtering decision can also include the L2TP
> packet type (control or data), protocol version (2 or 3) and
> encapsulation type (UDP or IP).
> 
> The most common use for this will likely be to filter L2TP data
> packets of individual L2TP tunnels or sessions. While a u32 match can
> be used, the L2TP protocol headers are such that field offsets differ
> depending on bits set in the header, making rules for matching generic
> L2TP connections cumbersome. This match extension takes care of all
> that.
> 
> An iptables patch will be submitted separately.
> 
> ---
> Changes in v2:
> Address comments from Patrick McHardy:-
> Added checkentry function to check args passed into kernel.
> 
> Changes in v3:
> Address comments from Pablo Neira Ayuso:-
> Remove debug code.
> Avoid multiple nested if statements when they are unnecessary.
> Fix data access to use skb_header_pointer() properly.
> Use #defines for L2TP packet header bit definitions.
> Improve comments to clarify how variations in L2TP header fiekld
> locations are handled when parsing header fields.
> 
> Signed-off-by: James Chapman <jchapman@xxxxxxxxxxx>
> ---
>  include/uapi/linux/netfilter/xt_l2tp.h |   36 ++++
>  net/netfilter/Kconfig                  |   10 +
>  net/netfilter/Makefile                 |    1 +
>  net/netfilter/xt_l2tp.c                |  355 ++++++++++++++++++++++++++++++++
>  4 files changed, 402 insertions(+), 0 deletions(-)
>  create mode 100644 include/uapi/linux/netfilter/xt_l2tp.h
>  create mode 100644 net/netfilter/xt_l2tp.c
> 
> diff --git a/include/uapi/linux/netfilter/xt_l2tp.h b/include/uapi/linux/netfilter/xt_l2tp.h
> new file mode 100644
> index 0000000..ba0a3ed
> --- /dev/null
> +++ b/include/uapi/linux/netfilter/xt_l2tp.h
> @@ -0,0 +1,36 @@
> +#ifndef _LINUX_NETFILTER_XT_L2TP_H
> +#define _LINUX_NETFILTER_XT_L2TP_H
> +
> +#include <linux/types.h>
> +
> +enum xt_l2tp_encap {
> +	XT_L2TP_ENCAP_UDP,
> +	XT_L2TP_ENCAP_IP,
> +};
> +
> +enum xt_l2tp_type {
> +	XT_L2TP_TYPE_CONTROL,
> +	XT_L2TP_TYPE_DATA,
> +};
> +
> +/* L2TP matching stuff */
> +struct xt_l2tp_info {
> +	__u32 tid;			/* tunnel id */
> +	__u32 sid;			/* session id */
> +	__u8 version;			/* L2TP protocol version */
> +	__u8 encap;			/* L2TP encapsulation type */
> +	__u8 type;			/* L2TP packet type */
> +	__u8 flags;			/* which fields to match */
> +};
> +
> +enum {
> +	XT_L2TP_TID	= (1 << 0),	/* match L2TP tunnel id */
> +	XT_L2TP_SID	= (1 << 1),	/* match L2TP session id */
> +	XT_L2TP_VERSION	= (1 << 2),	/* match L2TP protocol version */
> +	XT_L2TP_ENCAP	= (1 << 3),	/* match L2TP encapsulation type */
> +	XT_L2TP_TYPE	= (1 << 4),	/* match L2TP packet type */
> +};
> +
> +
> +#endif /* _LINUX_NETFILTER_XT_L2TP_H */
> +
> diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
> index 48acec1..12daddc 100644
> --- a/net/netfilter/Kconfig
> +++ b/net/netfilter/Kconfig
> @@ -1055,6 +1055,16 @@ config NETFILTER_XT_MATCH_IPVS
>  
>  	  If unsure, say N.
>  
> +config NETFILTER_XT_MATCH_L2TP
> +	tristate '"l2tp" match support'
> +	depends on NETFILTER_ADVANCED
> +	default L2TP
> +	---help---
> +	This option adds an "L2TP" match, which allows you to match against
> +	L2TP protocol header fields.
> +
> +	To compile it as a module, choose M here. If unsure, say N.
> +
>  config NETFILTER_XT_MATCH_LENGTH
>  	tristate '"length" match support'
>  	depends on NETFILTER_ADVANCED
> diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
> index 394483b..564bf35 100644
> --- a/net/netfilter/Makefile
> +++ b/net/netfilter/Makefile
> @@ -135,6 +135,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o
>  obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o
>  obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o
>  obj-$(CONFIG_NETFILTER_XT_MATCH_IPVS) += xt_ipvs.o
> +obj-$(CONFIG_NETFILTER_XT_MATCH_L2TP) += xt_l2tp.o
>  obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o
>  obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o
>  obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o
> diff --git a/net/netfilter/xt_l2tp.c b/net/netfilter/xt_l2tp.c
> new file mode 100644
> index 0000000..b7c060e
> --- /dev/null
> +++ b/net/netfilter/xt_l2tp.c
> @@ -0,0 +1,355 @@
> +/* Kernel module to match L2TP header parameters. */
> +
> +/* (C) 2013      James Chapman <jchapman@xxxxxxxxxxx>
> + *
> + * 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.
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +#include <linux/module.h>
> +#include <linux/skbuff.h>
> +#include <linux/if_ether.h>
> +#include <net/ip.h>
> +#include <linux/ipv6.h>
> +#include <net/ipv6.h>
> +#include <net/udp.h>
> +#include <linux/l2tp.h>
> +
> +#include <linux/netfilter_ipv4.h>
> +#include <linux/netfilter_ipv6.h>
> +#include <linux/netfilter/xt_l2tp.h>
> +#include <linux/netfilter/x_tables.h>
> +
> +/* L2TP header masks */
> +#define L2TP_HDR_T_BIT	0x8000
> +#define L2TP_HDR_L_BIT	0x4000
> +#define L2TP_HDR_VER	0x000f
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("James Chapman <jchapman@xxxxxxxxxxx>");
> +MODULE_DESCRIPTION("Xtables: L2TP header match");
> +MODULE_ALIAS("ipt_l2tp");
> +MODULE_ALIAS("ip6t_l2tp");
> +
> +/* The L2TP fields that can be matched */
> +struct l2tp_data {
> +	u32 tid;
> +	u32 sid;
> +	u8 type;
> +	u8 version;
> +	u8 encap;
> +};
> +
> +union l2tp_val {
> +	__be16 val16[2];
> +	__be32 val32;
> +};
> +
> +static bool l2tp_match(const struct xt_l2tp_info *info, struct l2tp_data *data)
> +{
> +	if ((info->flags & XT_L2TP_TYPE) && (info->type != data->type))
> +		return false;
> +
> +	if ((info->flags & XT_L2TP_ENCAP) && (info->encap != data->encap))
> +		return false;
> +
> +	if ((info->flags & XT_L2TP_VERSION) && (info->version != data->version))
> +		return false;
> +
> +	/* Check tid only for L2TPv3 control or any L2TPv2 packets */
> +	if ((info->flags & XT_L2TP_TID) &&
> +	    ((data->type == XT_L2TP_TYPE_CONTROL) || (data->version == 2)) &&
> +	    (info->tid != data->tid))
> +		return false;
> +
> +	/* Check sid only for L2TP data packets */
> +	if ((info->flags & XT_L2TP_SID) && (data->type == XT_L2TP_TYPE_DATA) &&
> +	    (info->sid != data->sid))
> +		return false;
> +
> +	return true;
> +}
> +
> +/* Parse L2TP header fields when UDP encapsulation is used. Handles
> + * L2TPv2 and L2TPv3.
> + *
> + * L2TPv2:
> + *  0                   1                   2                   3
> + *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + * |T|L|x|x|S|x|O|P|x|x|x|x|  Ver  |          Length (opt)         |
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + * |           Tunnel ID           |           Session ID          |
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + * |             Ns (opt)          |             Nr (opt)          |
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + * |      Offset Size (opt)        |    Offset pad... (opt)
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + *
> + * L2TPv3 control packets:
> + *  0                   1                   2                   3
> + *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + * |T|L|x|x|S|x|x|x|x|x|x|x|  Ver  |             Length            |
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + * |                     Control Connection ID                     |
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + * |               Ns              |               Nr              |
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

I see, this header above comes from rfc3931 (3.2.1. L2TP Control
Message Header), I'm telling this because...

> + *
> + * L2TPv3 data packets:
> + *  0                   1                   2                   3
> + *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + * |T|x|x|x|x|x|x|x|x|x|x|x|  Ver  |          Reserved             |
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + * |                           Session ID                          |
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + * |               Cookie (optional, maximum 64 bits)...
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + *                                                                 |
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

I don't think this is the right place to put these header
descriptions, perhaps a single line telling something like:

/* See RFC3931 (3.2.1. L2TP Control Message Header) for L2TPv3 header */

Something more minimalistic, but still informational. We would save
many lines in that .c file.

> + */
> +static bool l2tp_udp_mt(const struct sk_buff *skb, struct xt_action_param *par)
> +{
> +	const struct xt_l2tp_info *info = par->matchinfo;
> +	int uhlen = sizeof(struct udphdr);
> +	int offs = par->thoff + uhlen;
> +	bool ret;
> +	union l2tp_val *lh;
> +	union l2tp_val lhbuf;
> +	u16 flags;
> +	struct l2tp_data data = { 0, };
> +
> +	if (par->fragoff != 0)
> +		return false;
> +
> +	/* Extract L2TP header fields. The flags in the first 16 bits
> +	 * tell us where the other fields are.
> +	 */
> +	lh = skb_header_pointer(skb, offs, 2, &lhbuf);
> +	if (lh == NULL)
> +		return false;
> +
> +	flags = ntohs(lh->val16[0]);
> +	if (flags & L2TP_HDR_T_BIT)
> +		data.type = XT_L2TP_TYPE_CONTROL;
> +	else
> +		data.type = XT_L2TP_TYPE_DATA;
> +	data.version = (u8) flags & L2TP_HDR_VER;
> +
> +	/* Now extract the L2TP tid/sid. These are in different places
> +	 * for L2TPv2 (rfc2661) and L2TPv3 (rfc3931). For L2TPv2, we
> +	 * must also check to see if the length field is present,
> +	 * since this affects the offsets into the packet of the
> +	 * tid/sid fields.
> +	 */
> +	if (data.version == 3) {
> +		lh = skb_header_pointer(skb, offs + 4, 4, &lhbuf);
> +		if (lh == NULL)
> +			return false;
> +		if (data.type == XT_L2TP_TYPE_CONTROL)
> +			data.tid = ntohl(lh->val32);
> +		else
> +			data.sid = ntohl(lh->val32);
> +	} else if (data.version == 2) {
> +		if (flags & L2TP_HDR_L_BIT)
> +			offs += 2;
> +		lh = skb_header_pointer(skb, offs + 2, 4, &lhbuf);
> +		if (lh == NULL)
> +			return false;
> +		data.tid = (u32) ntohs(lh->val16[0]);
> +		data.sid = (u32) ntohs(lh->val16[1]);
> +	} else
> +		return false;
> +
> +	data.encap = XT_L2TP_ENCAP_UDP;
> +
> +	ret = l2tp_match(info, &data);
> +
> +	return ret;
> +}
> +
> +/* Parse L2TP header fields when IP encapsulation (no UDP header).
> + *
> + * L2TPv3 control packets:
> + *  0                   1                   2                   3
> + *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + * |                      (32 bits of zeros)                       |
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + * |T|L|x|x|S|x|x|x|x|x|x|x|  Ver  |             Length            |
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + * |                     Control Connection ID                     |
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + * |               Ns              |               Nr              |
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + *
> + * L2TPv3 data packets:
> + *  0                   1                   2                   3
> + *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + * |                           Session ID                          |
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + * |               Cookie (optional, maximum 64 bits)...
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + *                                                                 |
> + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> + */
> +static bool l2tp_ip_mt(const struct sk_buff *skb, struct xt_action_param *par)
> +{
> +	const struct xt_l2tp_info *info = par->matchinfo;
> +	bool ret;
> +	union l2tp_val *lh;
> +	union l2tp_val lhbuf;
> +	struct l2tp_data data = { 0, };
> +
> +	if (par->fragoff != 0)
> +		return false;
> +
> +	/* For IP encap, the L2TP sid is the first 32-bits. */
> +	lh = skb_header_pointer(skb, par->thoff, sizeof(lhbuf), &lhbuf);
> +	if (lh == NULL)
> +		return false;
> +	if (lh->val32 == 0) {
> +		/* Must be a control packet. The L2TP tid is further
> +		 * into the packet.
> +		 */
> +		data.type = XT_L2TP_TYPE_CONTROL;
> +		lh = skb_header_pointer(skb, par->thoff + 8, sizeof(lhbuf),
> +					&lhbuf);
> +		if (lh == NULL)
> +			return false;
> +		data.tid = ntohl(lh->val32);
> +	} else {
> +		data.sid = ntohl(lh->val32);
> +		data.type = XT_L2TP_TYPE_DATA;
> +	}
> +
> +	data.version = 3;
> +	data.encap = XT_L2TP_ENCAP_IP;
> +
> +	ret = l2tp_match(info, &data);
> +
> +	return ret;
> +}
> +
> +static bool l2tp_mt_common(const struct sk_buff *skb, struct xt_action_param *par, u8 ipproto)
> +{
> +	bool ret;
> +
> +	/* The L2TP header is different depending on whether UDP or IP
> +	 * encapsulation is used.
> +	 */
> +	switch (ipproto) {

The match is selecting the code path to be executed depending on the
packet header, I prefer if your users explicitly specify what L2TP
mode they want to match via iptables option, eg. -p udp.

> +	case IPPROTO_UDP:
> +		ret = l2tp_udp_mt(skb, par);
> +		break;
> +	case IPPROTO_L2TP:
> +		ret = l2tp_ip_mt(skb, par);
> +		break;
> +	default:
> +		return false;
> +	}
> +
> +	return ret;
> +}
> +
> +static bool l2tp_mt4(const struct sk_buff *skb, struct xt_action_param *par)
> +{
> +	struct iphdr *iph = ip_hdr(skb);
> +	u8 ipproto = iph->protocol;
> +
> +	return l2tp_mt_common(skb, par, ipproto);
> +}
> +
> +static bool l2tp_mt6(const struct sk_buff *skb, struct xt_action_param *par)
> +{
> +	struct ipv6hdr *ip6h = ipv6_hdr(skb);
> +	u8 ipproto = ip6h->nexthdr;

I'm afraid this won't work for IPv6 in all cases as it is assuming
that the UDP header will come just after the IPv6 header. But you may
still see a fragmentation extension there.

You have two choices to fix this:

* The matching mode depends on if -p udp was specified, otherwise IP mode
  is assumed. The ip6_tables core already sets par->thoff for you in
  that case.

* If no -p is passed, then you have to add some special handling for
  extension headers in IPv6, please see ipv6_find_hdr().

> +
> +	return l2tp_mt_common(skb, par, ipproto);
> +}
> +
> +static int l2tp_mt_check(const struct xt_mtchk_param *par)
> +{
> +	struct xt_l2tp_info *info = par->matchinfo;
> +
> +	/* Check for invalid flags */
> +	if (info->flags & ~(XT_L2TP_TID | XT_L2TP_SID | XT_L2TP_VERSION |
> +			    XT_L2TP_ENCAP | XT_L2TP_TYPE))
> +		return -EINVAL;
> +
> +	/* At least one of tid, sid or type=control must be specified */
> +	if ((!(info->flags & XT_L2TP_TID)) &&
> +	    (!(info->flags & XT_L2TP_SID)) &&
> +	    ((!(info->flags & XT_L2TP_TYPE)) ||
> +	     (info->type != XT_L2TP_TYPE_CONTROL)))
> +		return -EINVAL;
> +
> +	/* If version 2 is specified, check that incompatible params
> +	 * are not supplied
> +	 */
> +	if (info->flags & XT_L2TP_VERSION) {
> +		if ((info->version < 2) || (info->version > 3))
> +			return -EINVAL;
> +
> +		if (info->version == 2) {
> +			if ((info->flags & XT_L2TP_TID) &&
> +			    (info->tid > 0xffff))
> +				return -EINVAL;
> +			if ((info->flags & XT_L2TP_SID) &&
> +			    (info->sid > 0xffff))
> +				return -EINVAL;
> +			if ((info->flags & XT_L2TP_ENCAP) &&
> +			    (info->encap == XT_L2TP_ENCAP_IP))
> +				return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static struct xt_match l2tp_mt_reg[] __read_mostly = {
> +	{
> +		.name      = "l2tp",
> +		.revision  = 0,
> +		.family    = NFPROTO_IPV4,
> +		.match     = l2tp_mt4,
> +		.matchsize = XT_ALIGN(sizeof(struct xt_l2tp_info)),
> +		.checkentry = l2tp_mt_check,
> +		.hooks     = ((1 << NF_INET_PRE_ROUTING) |
> +			      (1 << NF_INET_LOCAL_IN) |
> +			      (1 << NF_INET_LOCAL_OUT) |
> +			      (1 << NF_INET_FORWARD)),
> +		.me        = THIS_MODULE,
> +	},
> +	{
> +		.name      = "l2tp",
> +		.revision  = 0,
> +		.family    = NFPROTO_IPV6,
> +		.match     = l2tp_mt6,
> +		.matchsize = XT_ALIGN(sizeof(struct xt_l2tp_info)),
> +		.checkentry = l2tp_mt_check,
> +		.hooks     = ((1 << NF_INET_PRE_ROUTING) |
> +			      (1 << NF_INET_LOCAL_IN) |
> +			      (1 << NF_INET_LOCAL_OUT) |
> +			      (1 << NF_INET_FORWARD)),
> +		.me        = THIS_MODULE,
> +	},
> +};
> +
> +static int __init l2tp_mt_init(void)
> +{
> +	return xt_register_matches(&l2tp_mt_reg[0], ARRAY_SIZE(l2tp_mt_reg));
> +}
> +
> +static void __exit l2tp_mt_exit(void)
> +{
> +	xt_unregister_matches(&l2tp_mt_reg[0], ARRAY_SIZE(l2tp_mt_reg));
> +}
> +
> +module_init(l2tp_mt_init);
> +module_exit(l2tp_mt_exit);
> -- 
> 1.7.0.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux