Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: introduce l2tp match extension

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.

Signed-off-by: James Chapman <jchapman@katalix.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

James Chapman and committed by
Pablo Neira Ayuso
74f77a6b d0eb1f7e

+393
+1
include/uapi/linux/netfilter/Kbuild
··· 58 58 header-y += xt_ipcomp.h 59 59 header-y += xt_iprange.h 60 60 header-y += xt_ipvs.h 61 + header-y += xt_l2tp.h 61 62 header-y += xt_length.h 62 63 header-y += xt_limit.h 63 64 header-y += xt_mac.h
+27
include/uapi/linux/netfilter/xt_l2tp.h
··· 1 + #ifndef _LINUX_NETFILTER_XT_L2TP_H 2 + #define _LINUX_NETFILTER_XT_L2TP_H 3 + 4 + #include <linux/types.h> 5 + 6 + enum xt_l2tp_type { 7 + XT_L2TP_TYPE_CONTROL, 8 + XT_L2TP_TYPE_DATA, 9 + }; 10 + 11 + /* L2TP matching stuff */ 12 + struct xt_l2tp_info { 13 + __u32 tid; /* tunnel id */ 14 + __u32 sid; /* session id */ 15 + __u8 version; /* L2TP protocol version */ 16 + __u8 type; /* L2TP packet type */ 17 + __u8 flags; /* which fields to match */ 18 + }; 19 + 20 + enum { 21 + XT_L2TP_TID = (1 << 0), /* match L2TP tunnel id */ 22 + XT_L2TP_SID = (1 << 1), /* match L2TP session id */ 23 + XT_L2TP_VERSION = (1 << 2), /* match L2TP protocol version */ 24 + XT_L2TP_TYPE = (1 << 3), /* match L2TP packet type */ 25 + }; 26 + 27 + #endif /* _LINUX_NETFILTER_XT_L2TP_H */
+10
net/netfilter/Kconfig
··· 1131 1131 1132 1132 If unsure, say N. 1133 1133 1134 + config NETFILTER_XT_MATCH_L2TP 1135 + tristate '"l2tp" match support' 1136 + depends on NETFILTER_ADVANCED 1137 + default L2TP 1138 + ---help--- 1139 + This option adds an "L2TP" match, which allows you to match against 1140 + L2TP protocol header fields. 1141 + 1142 + To compile it as a module, choose M here. If unsure, say N. 1143 + 1134 1144 config NETFILTER_XT_MATCH_LENGTH 1135 1145 tristate '"length" match support' 1136 1146 depends on NETFILTER_ADVANCED
+1
net/netfilter/Makefile
··· 137 137 obj-$(CONFIG_NETFILTER_XT_MATCH_IPCOMP) += xt_ipcomp.o 138 138 obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o 139 139 obj-$(CONFIG_NETFILTER_XT_MATCH_IPVS) += xt_ipvs.o 140 + obj-$(CONFIG_NETFILTER_XT_MATCH_L2TP) += xt_l2tp.o 140 141 obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o 141 142 obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o 142 143 obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o
+354
net/netfilter/xt_l2tp.c
··· 1 + /* Kernel module to match L2TP header parameters. */ 2 + 3 + /* (C) 2013 James Chapman <jchapman@katalix.com> 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + */ 9 + 10 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 11 + #include <linux/module.h> 12 + #include <linux/skbuff.h> 13 + #include <linux/if_ether.h> 14 + #include <net/ip.h> 15 + #include <linux/ipv6.h> 16 + #include <net/ipv6.h> 17 + #include <net/udp.h> 18 + #include <linux/l2tp.h> 19 + 20 + #include <linux/netfilter_ipv4.h> 21 + #include <linux/netfilter_ipv6.h> 22 + #include <linux/netfilter_ipv4/ip_tables.h> 23 + #include <linux/netfilter_ipv6/ip6_tables.h> 24 + #include <linux/netfilter/x_tables.h> 25 + #include <linux/netfilter/xt_tcpudp.h> 26 + #include <linux/netfilter/xt_l2tp.h> 27 + 28 + /* L2TP header masks */ 29 + #define L2TP_HDR_T_BIT 0x8000 30 + #define L2TP_HDR_L_BIT 0x4000 31 + #define L2TP_HDR_VER 0x000f 32 + 33 + MODULE_LICENSE("GPL"); 34 + MODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); 35 + MODULE_DESCRIPTION("Xtables: L2TP header match"); 36 + MODULE_ALIAS("ipt_l2tp"); 37 + MODULE_ALIAS("ip6t_l2tp"); 38 + 39 + /* The L2TP fields that can be matched */ 40 + struct l2tp_data { 41 + u32 tid; 42 + u32 sid; 43 + u8 type; 44 + u8 version; 45 + }; 46 + 47 + union l2tp_val { 48 + __be16 val16[2]; 49 + __be32 val32; 50 + }; 51 + 52 + static bool l2tp_match(const struct xt_l2tp_info *info, struct l2tp_data *data) 53 + { 54 + if ((info->flags & XT_L2TP_TYPE) && (info->type != data->type)) 55 + return false; 56 + 57 + if ((info->flags & XT_L2TP_VERSION) && (info->version != data->version)) 58 + return false; 59 + 60 + /* Check tid only for L2TPv3 control or any L2TPv2 packets */ 61 + if ((info->flags & XT_L2TP_TID) && 62 + ((data->type == XT_L2TP_TYPE_CONTROL) || (data->version == 2)) && 63 + (info->tid != data->tid)) 64 + return false; 65 + 66 + /* Check sid only for L2TP data packets */ 67 + if ((info->flags & XT_L2TP_SID) && (data->type == XT_L2TP_TYPE_DATA) && 68 + (info->sid != data->sid)) 69 + return false; 70 + 71 + return true; 72 + } 73 + 74 + /* Parse L2TP header fields when UDP encapsulation is used. Handles 75 + * L2TPv2 and L2TPv3. Note the L2TPv3 control and data packets have a 76 + * different format. See 77 + * RFC2661, Section 3.1, L2TPv2 Header Format 78 + * RFC3931, Section 3.2.1, L2TPv3 Control Message Header 79 + * RFC3931, Section 3.2.2, L2TPv3 Data Message Header 80 + * RFC3931, Section 4.1.2.1, L2TPv3 Session Header over UDP 81 + */ 82 + static bool l2tp_udp_mt(const struct sk_buff *skb, struct xt_action_param *par, u16 thoff) 83 + { 84 + const struct xt_l2tp_info *info = par->matchinfo; 85 + int uhlen = sizeof(struct udphdr); 86 + int offs = thoff + uhlen; 87 + union l2tp_val *lh; 88 + union l2tp_val lhbuf; 89 + u16 flags; 90 + struct l2tp_data data = { 0, }; 91 + 92 + if (par->fragoff != 0) 93 + return false; 94 + 95 + /* Extract L2TP header fields. The flags in the first 16 bits 96 + * tell us where the other fields are. 97 + */ 98 + lh = skb_header_pointer(skb, offs, 2, &lhbuf); 99 + if (lh == NULL) 100 + return false; 101 + 102 + flags = ntohs(lh->val16[0]); 103 + if (flags & L2TP_HDR_T_BIT) 104 + data.type = XT_L2TP_TYPE_CONTROL; 105 + else 106 + data.type = XT_L2TP_TYPE_DATA; 107 + data.version = (u8) flags & L2TP_HDR_VER; 108 + 109 + /* Now extract the L2TP tid/sid. These are in different places 110 + * for L2TPv2 (rfc2661) and L2TPv3 (rfc3931). For L2TPv2, we 111 + * must also check to see if the length field is present, 112 + * since this affects the offsets into the packet of the 113 + * tid/sid fields. 114 + */ 115 + if (data.version == 3) { 116 + lh = skb_header_pointer(skb, offs + 4, 4, &lhbuf); 117 + if (lh == NULL) 118 + return false; 119 + if (data.type == XT_L2TP_TYPE_CONTROL) 120 + data.tid = ntohl(lh->val32); 121 + else 122 + data.sid = ntohl(lh->val32); 123 + } else if (data.version == 2) { 124 + if (flags & L2TP_HDR_L_BIT) 125 + offs += 2; 126 + lh = skb_header_pointer(skb, offs + 2, 4, &lhbuf); 127 + if (lh == NULL) 128 + return false; 129 + data.tid = (u32) ntohs(lh->val16[0]); 130 + data.sid = (u32) ntohs(lh->val16[1]); 131 + } else 132 + return false; 133 + 134 + return l2tp_match(info, &data); 135 + } 136 + 137 + /* Parse L2TP header fields for IP encapsulation (no UDP header). 138 + * L2TPv3 data packets have a different form with IP encap. See 139 + * RC3931, Section 4.1.1.1, L2TPv3 Session Header over IP. 140 + * RC3931, Section 4.1.1.2, L2TPv3 Control and Data Traffic over IP. 141 + */ 142 + static bool l2tp_ip_mt(const struct sk_buff *skb, struct xt_action_param *par, u16 thoff) 143 + { 144 + const struct xt_l2tp_info *info = par->matchinfo; 145 + union l2tp_val *lh; 146 + union l2tp_val lhbuf; 147 + struct l2tp_data data = { 0, }; 148 + 149 + /* For IP encap, the L2TP sid is the first 32-bits. */ 150 + lh = skb_header_pointer(skb, thoff, sizeof(lhbuf), &lhbuf); 151 + if (lh == NULL) 152 + return false; 153 + if (lh->val32 == 0) { 154 + /* Must be a control packet. The L2TP tid is further 155 + * into the packet. 156 + */ 157 + data.type = XT_L2TP_TYPE_CONTROL; 158 + lh = skb_header_pointer(skb, thoff + 8, sizeof(lhbuf), 159 + &lhbuf); 160 + if (lh == NULL) 161 + return false; 162 + data.tid = ntohl(lh->val32); 163 + } else { 164 + data.sid = ntohl(lh->val32); 165 + data.type = XT_L2TP_TYPE_DATA; 166 + } 167 + 168 + data.version = 3; 169 + 170 + return l2tp_match(info, &data); 171 + } 172 + 173 + static bool l2tp_mt4(const struct sk_buff *skb, struct xt_action_param *par) 174 + { 175 + struct iphdr *iph = ip_hdr(skb); 176 + u8 ipproto = iph->protocol; 177 + 178 + /* l2tp_mt_check4 already restricts the transport protocol */ 179 + switch (ipproto) { 180 + case IPPROTO_UDP: 181 + return l2tp_udp_mt(skb, par, par->thoff); 182 + case IPPROTO_L2TP: 183 + return l2tp_ip_mt(skb, par, par->thoff); 184 + } 185 + 186 + return false; 187 + } 188 + 189 + #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 190 + static bool l2tp_mt6(const struct sk_buff *skb, struct xt_action_param *par) 191 + { 192 + unsigned int thoff = 0; 193 + unsigned short fragoff = 0; 194 + int ipproto; 195 + 196 + ipproto = ipv6_find_hdr(skb, &thoff, -1, &fragoff, NULL); 197 + if (fragoff != 0) 198 + return false; 199 + 200 + /* l2tp_mt_check6 already restricts the transport protocol */ 201 + switch (ipproto) { 202 + case IPPROTO_UDP: 203 + return l2tp_udp_mt(skb, par, thoff); 204 + case IPPROTO_L2TP: 205 + return l2tp_ip_mt(skb, par, thoff); 206 + } 207 + 208 + return false; 209 + } 210 + #endif 211 + 212 + static int l2tp_mt_check(const struct xt_mtchk_param *par) 213 + { 214 + const struct xt_l2tp_info *info = par->matchinfo; 215 + 216 + /* Check for invalid flags */ 217 + if (info->flags & ~(XT_L2TP_TID | XT_L2TP_SID | XT_L2TP_VERSION | 218 + XT_L2TP_TYPE)) { 219 + pr_info("unknown flags: %x\n", info->flags); 220 + return -EINVAL; 221 + } 222 + 223 + /* At least one of tid, sid or type=control must be specified */ 224 + if ((!(info->flags & XT_L2TP_TID)) && 225 + (!(info->flags & XT_L2TP_SID)) && 226 + ((!(info->flags & XT_L2TP_TYPE)) || 227 + (info->type != XT_L2TP_TYPE_CONTROL))) { 228 + pr_info("invalid flags combination: %x\n", info->flags); 229 + return -EINVAL; 230 + } 231 + 232 + /* If version 2 is specified, check that incompatible params 233 + * are not supplied 234 + */ 235 + if (info->flags & XT_L2TP_VERSION) { 236 + if ((info->version < 2) || (info->version > 3)) { 237 + pr_info("wrong L2TP version: %u\n", info->version); 238 + return -EINVAL; 239 + } 240 + 241 + if (info->version == 2) { 242 + if ((info->flags & XT_L2TP_TID) && 243 + (info->tid > 0xffff)) { 244 + pr_info("v2 tid > 0xffff: %u\n", info->tid); 245 + return -EINVAL; 246 + } 247 + if ((info->flags & XT_L2TP_SID) && 248 + (info->sid > 0xffff)) { 249 + pr_info("v2 sid > 0xffff: %u\n", info->sid); 250 + return -EINVAL; 251 + } 252 + } 253 + } 254 + 255 + return 0; 256 + } 257 + 258 + static int l2tp_mt_check4(const struct xt_mtchk_param *par) 259 + { 260 + const struct xt_l2tp_info *info = par->matchinfo; 261 + const struct ipt_entry *e = par->entryinfo; 262 + const struct ipt_ip *ip = &e->ip; 263 + int ret; 264 + 265 + ret = l2tp_mt_check(par); 266 + if (ret != 0) 267 + return ret; 268 + 269 + if ((ip->proto != IPPROTO_UDP) && 270 + (ip->proto != IPPROTO_L2TP)) { 271 + pr_info("missing protocol rule (udp|l2tpip)\n"); 272 + return -EINVAL; 273 + } 274 + 275 + if ((ip->proto == IPPROTO_L2TP) && 276 + (info->version == 2)) { 277 + pr_info("v2 doesn't support IP mode\n"); 278 + return -EINVAL; 279 + } 280 + 281 + return 0; 282 + } 283 + 284 + #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 285 + static int l2tp_mt_check6(const struct xt_mtchk_param *par) 286 + { 287 + const struct xt_l2tp_info *info = par->matchinfo; 288 + const struct ip6t_entry *e = par->entryinfo; 289 + const struct ip6t_ip6 *ip = &e->ipv6; 290 + int ret; 291 + 292 + ret = l2tp_mt_check(par); 293 + if (ret != 0) 294 + return ret; 295 + 296 + if ((ip->proto != IPPROTO_UDP) && 297 + (ip->proto != IPPROTO_L2TP)) { 298 + pr_info("missing protocol rule (udp|l2tpip)\n"); 299 + return -EINVAL; 300 + } 301 + 302 + if ((ip->proto == IPPROTO_L2TP) && 303 + (info->version == 2)) { 304 + pr_info("v2 doesn't support IP mode\n"); 305 + return -EINVAL; 306 + } 307 + 308 + return 0; 309 + } 310 + #endif 311 + 312 + static struct xt_match l2tp_mt_reg[] __read_mostly = { 313 + { 314 + .name = "l2tp", 315 + .revision = 0, 316 + .family = NFPROTO_IPV4, 317 + .match = l2tp_mt4, 318 + .matchsize = XT_ALIGN(sizeof(struct xt_l2tp_info)), 319 + .checkentry = l2tp_mt_check4, 320 + .hooks = ((1 << NF_INET_PRE_ROUTING) | 321 + (1 << NF_INET_LOCAL_IN) | 322 + (1 << NF_INET_LOCAL_OUT) | 323 + (1 << NF_INET_FORWARD)), 324 + .me = THIS_MODULE, 325 + }, 326 + #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 327 + { 328 + .name = "l2tp", 329 + .revision = 0, 330 + .family = NFPROTO_IPV6, 331 + .match = l2tp_mt6, 332 + .matchsize = XT_ALIGN(sizeof(struct xt_l2tp_info)), 333 + .checkentry = l2tp_mt_check6, 334 + .hooks = ((1 << NF_INET_PRE_ROUTING) | 335 + (1 << NF_INET_LOCAL_IN) | 336 + (1 << NF_INET_LOCAL_OUT) | 337 + (1 << NF_INET_FORWARD)), 338 + .me = THIS_MODULE, 339 + }, 340 + #endif 341 + }; 342 + 343 + static int __init l2tp_mt_init(void) 344 + { 345 + return xt_register_matches(&l2tp_mt_reg[0], ARRAY_SIZE(l2tp_mt_reg)); 346 + } 347 + 348 + static void __exit l2tp_mt_exit(void) 349 + { 350 + xt_unregister_matches(&l2tp_mt_reg[0], ARRAY_SIZE(l2tp_mt_reg)); 351 + } 352 + 353 + module_init(l2tp_mt_init); 354 + module_exit(l2tp_mt_exit);