netfilter: xt_socket: add XT_SOCKET_NOWILDCARD flag
[cascardo/linux.git] / net / netfilter / xt_socket.c
index 0270424..f8b7191 100644 (file)
@@ -163,8 +163,11 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
                bool wildcard;
                bool transparent = true;
 
-               /* Ignore sockets listening on INADDR_ANY */
-               wildcard = (sk->sk_state != TCP_TIME_WAIT &&
+               /* Ignore sockets listening on INADDR_ANY,
+                * unless XT_SOCKET_NOWILDCARD is set
+                */
+               wildcard = (!(info->flags & XT_SOCKET_NOWILDCARD) &&
+                           sk->sk_state != TCP_TIME_WAIT &&
                            inet_sk(sk)->inet_rcv_saddr == 0);
 
                /* Ignore non-transparent sockets,
@@ -197,7 +200,7 @@ socket_mt4_v0(const struct sk_buff *skb, struct xt_action_param *par)
 }
 
 static bool
-socket_mt4_v1(const struct sk_buff *skb, struct xt_action_param *par)
+socket_mt4_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
 {
        return socket_match(skb, par, par->matchinfo);
 }
@@ -259,7 +262,7 @@ extract_icmp6_fields(const struct sk_buff *skb,
 }
 
 static bool
-socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par)
+socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
 {
        struct ipv6hdr *iph = ipv6_hdr(skb);
        struct udphdr _hdr, *hp = NULL;
@@ -302,8 +305,11 @@ socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par)
                bool wildcard;
                bool transparent = true;
 
-               /* Ignore sockets listening on INADDR_ANY */
-               wildcard = (sk->sk_state != TCP_TIME_WAIT &&
+               /* Ignore sockets listening on INADDR_ANY
+                * unless XT_SOCKET_NOWILDCARD is set
+                */
+               wildcard = (!(info->flags & XT_SOCKET_NOWILDCARD) &&
+                           sk->sk_state != TCP_TIME_WAIT &&
                            ipv6_addr_any(&inet6_sk(sk)->rcv_saddr));
 
                /* Ignore non-transparent sockets,
@@ -331,6 +337,28 @@ socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par)
 }
 #endif
 
+static int socket_mt_v1_check(const struct xt_mtchk_param *par)
+{
+       const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;
+
+       if (info->flags & ~XT_SOCKET_FLAGS_V1) {
+               pr_info("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V1);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int socket_mt_v2_check(const struct xt_mtchk_param *par)
+{
+       const struct xt_socket_mtinfo2 *info = (struct xt_socket_mtinfo2 *) par->matchinfo;
+
+       if (info->flags & ~XT_SOCKET_FLAGS_V2) {
+               pr_info("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V2);
+               return -EINVAL;
+       }
+       return 0;
+}
+
 static struct xt_match socket_mt_reg[] __read_mostly = {
        {
                .name           = "socket",
@@ -345,7 +373,8 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
                .name           = "socket",
                .revision       = 1,
                .family         = NFPROTO_IPV4,
-               .match          = socket_mt4_v1,
+               .match          = socket_mt4_v1_v2,
+               .checkentry     = socket_mt_v1_check,
                .matchsize      = sizeof(struct xt_socket_mtinfo1),
                .hooks          = (1 << NF_INET_PRE_ROUTING) |
                                  (1 << NF_INET_LOCAL_IN),
@@ -356,7 +385,32 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
                .name           = "socket",
                .revision       = 1,
                .family         = NFPROTO_IPV6,
-               .match          = socket_mt6_v1,
+               .match          = socket_mt6_v1_v2,
+               .checkentry     = socket_mt_v1_check,
+               .matchsize      = sizeof(struct xt_socket_mtinfo1),
+               .hooks          = (1 << NF_INET_PRE_ROUTING) |
+                                 (1 << NF_INET_LOCAL_IN),
+               .me             = THIS_MODULE,
+       },
+#endif
+       {
+               .name           = "socket",
+               .revision       = 2,
+               .family         = NFPROTO_IPV4,
+               .match          = socket_mt4_v1_v2,
+               .checkentry     = socket_mt_v2_check,
+               .matchsize      = sizeof(struct xt_socket_mtinfo1),
+               .hooks          = (1 << NF_INET_PRE_ROUTING) |
+                                 (1 << NF_INET_LOCAL_IN),
+               .me             = THIS_MODULE,
+       },
+#ifdef XT_SOCKET_HAVE_IPV6
+       {
+               .name           = "socket",
+               .revision       = 2,
+               .family         = NFPROTO_IPV6,
+               .match          = socket_mt6_v1_v2,
+               .checkentry     = socket_mt_v2_check,
                .matchsize      = sizeof(struct xt_socket_mtinfo1),
                .hooks          = (1 << NF_INET_PRE_ROUTING) |
                                  (1 << NF_INET_LOCAL_IN),