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

netfilter: xt_socket: add XT_SOCKET_NOWILDCARD flag

xt_socket module can be a nice replacement to conntrack module
in some cases (SYN filtering for example)

But it lacks the ability to match the 3rd packet of TCP
handshake (ACK coming from the client).

Add a XT_SOCKET_NOWILDCARD flag to disable the wildcard mechanism.

The wildcard is the legacy socket match behavior, that ignores
LISTEN sockets bound to INADDR_ANY (or ipv6 equivalent)

iptables -I INPUT -p tcp --syn -j SYN_CHAIN
iptables -I INPUT -m socket --nowildcard -j ACCEPT

Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Patrick McHardy <kaber@trash.net>
Cc: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Eric Dumazet and committed by
Pablo Neira Ayuso
681f130f 6547a221

+69 -8
+7
include/uapi/linux/netfilter/xt_socket.h
··· 5 5 6 6 enum { 7 7 XT_SOCKET_TRANSPARENT = 1 << 0, 8 + XT_SOCKET_NOWILDCARD = 1 << 1, 8 9 }; 9 10 10 11 struct xt_socket_mtinfo1 { 11 12 __u8 flags; 12 13 }; 14 + #define XT_SOCKET_FLAGS_V1 XT_SOCKET_TRANSPARENT 15 + 16 + struct xt_socket_mtinfo2 { 17 + __u8 flags; 18 + }; 19 + #define XT_SOCKET_FLAGS_V2 (XT_SOCKET_TRANSPARENT | XT_SOCKET_NOWILDCARD) 13 20 14 21 #endif /* _XT_SOCKET_H */
+62 -8
net/netfilter/xt_socket.c
··· 163 163 bool wildcard; 164 164 bool transparent = true; 165 165 166 - /* Ignore sockets listening on INADDR_ANY */ 167 - wildcard = (sk->sk_state != TCP_TIME_WAIT && 166 + /* Ignore sockets listening on INADDR_ANY, 167 + * unless XT_SOCKET_NOWILDCARD is set 168 + */ 169 + wildcard = (!(info->flags & XT_SOCKET_NOWILDCARD) && 170 + sk->sk_state != TCP_TIME_WAIT && 168 171 inet_sk(sk)->inet_rcv_saddr == 0); 169 172 170 173 /* Ignore non-transparent sockets, ··· 200 197 } 201 198 202 199 static bool 203 - socket_mt4_v1(const struct sk_buff *skb, struct xt_action_param *par) 200 + socket_mt4_v1_v2(const struct sk_buff *skb, struct xt_action_param *par) 204 201 { 205 202 return socket_match(skb, par, par->matchinfo); 206 203 } ··· 262 259 } 263 260 264 261 static bool 265 - socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par) 262 + socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par) 266 263 { 267 264 struct ipv6hdr *iph = ipv6_hdr(skb); 268 265 struct udphdr _hdr, *hp = NULL; ··· 305 302 bool wildcard; 306 303 bool transparent = true; 307 304 308 - /* Ignore sockets listening on INADDR_ANY */ 309 - wildcard = (sk->sk_state != TCP_TIME_WAIT && 305 + /* Ignore sockets listening on INADDR_ANY 306 + * unless XT_SOCKET_NOWILDCARD is set 307 + */ 308 + wildcard = (!(info->flags & XT_SOCKET_NOWILDCARD) && 309 + sk->sk_state != TCP_TIME_WAIT && 310 310 ipv6_addr_any(&inet6_sk(sk)->rcv_saddr)); 311 311 312 312 /* Ignore non-transparent sockets, ··· 337 331 } 338 332 #endif 339 333 334 + static int socket_mt_v1_check(const struct xt_mtchk_param *par) 335 + { 336 + const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo; 337 + 338 + if (info->flags & ~XT_SOCKET_FLAGS_V1) { 339 + pr_info("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V1); 340 + return -EINVAL; 341 + } 342 + return 0; 343 + } 344 + 345 + static int socket_mt_v2_check(const struct xt_mtchk_param *par) 346 + { 347 + const struct xt_socket_mtinfo2 *info = (struct xt_socket_mtinfo2 *) par->matchinfo; 348 + 349 + if (info->flags & ~XT_SOCKET_FLAGS_V2) { 350 + pr_info("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V2); 351 + return -EINVAL; 352 + } 353 + return 0; 354 + } 355 + 340 356 static struct xt_match socket_mt_reg[] __read_mostly = { 341 357 { 342 358 .name = "socket", ··· 373 345 .name = "socket", 374 346 .revision = 1, 375 347 .family = NFPROTO_IPV4, 376 - .match = socket_mt4_v1, 348 + .match = socket_mt4_v1_v2, 349 + .checkentry = socket_mt_v1_check, 377 350 .matchsize = sizeof(struct xt_socket_mtinfo1), 378 351 .hooks = (1 << NF_INET_PRE_ROUTING) | 379 352 (1 << NF_INET_LOCAL_IN), ··· 385 356 .name = "socket", 386 357 .revision = 1, 387 358 .family = NFPROTO_IPV6, 388 - .match = socket_mt6_v1, 359 + .match = socket_mt6_v1_v2, 360 + .checkentry = socket_mt_v1_check, 361 + .matchsize = sizeof(struct xt_socket_mtinfo1), 362 + .hooks = (1 << NF_INET_PRE_ROUTING) | 363 + (1 << NF_INET_LOCAL_IN), 364 + .me = THIS_MODULE, 365 + }, 366 + #endif 367 + { 368 + .name = "socket", 369 + .revision = 2, 370 + .family = NFPROTO_IPV4, 371 + .match = socket_mt4_v1_v2, 372 + .checkentry = socket_mt_v2_check, 373 + .matchsize = sizeof(struct xt_socket_mtinfo1), 374 + .hooks = (1 << NF_INET_PRE_ROUTING) | 375 + (1 << NF_INET_LOCAL_IN), 376 + .me = THIS_MODULE, 377 + }, 378 + #ifdef XT_SOCKET_HAVE_IPV6 379 + { 380 + .name = "socket", 381 + .revision = 2, 382 + .family = NFPROTO_IPV6, 383 + .match = socket_mt6_v1_v2, 384 + .checkentry = socket_mt_v2_check, 389 385 .matchsize = sizeof(struct xt_socket_mtinfo1), 390 386 .hooks = (1 << NF_INET_PRE_ROUTING) | 391 387 (1 << NF_INET_LOCAL_IN),