diff options
| author | KOVACS Krisztian <hidden@sch.bme.hu> | 2008-10-08 05:35:12 -0400 |
|---|---|---|
| committer | Patrick McHardy <kaber@trash.net> | 2008-10-08 05:35:12 -0400 |
| commit | 136cdc71fd54e77463e570643ac76e2b696e48a0 (patch) | |
| tree | 89006778803d098a8f991ebeacc2dd86a2782340 /net/netfilter | |
| parent | 9ad2d745a23853927a19789b034d9eb2e62d78ee (diff) | |
netfilter: iptables socket match
Add iptables 'socket' match, which matches packets for which a TCP/UDP
socket lookup succeeds.
Signed-off-by: KOVACS Krisztian <hidden@sch.bme.hu>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net/netfilter')
| -rw-r--r-- | net/netfilter/Kconfig | 15 | ||||
| -rw-r--r-- | net/netfilter/Makefile | 1 | ||||
| -rw-r--r-- | net/netfilter/xt_socket.c | 192 |
3 files changed, 208 insertions, 0 deletions
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index ed1dcfb61e12..f6c807299487 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
| @@ -778,6 +778,21 @@ config NETFILTER_XT_MATCH_SCTP | |||
| 778 | If you want to compile it as a module, say M here and read | 778 | If you want to compile it as a module, say M here and read |
| 779 | <file:Documentation/kbuild/modules.txt>. If unsure, say `N'. | 779 | <file:Documentation/kbuild/modules.txt>. If unsure, say `N'. |
| 780 | 780 | ||
| 781 | config NETFILTER_XT_MATCH_SOCKET | ||
| 782 | tristate '"socket" match support (EXPERIMENTAL)' | ||
| 783 | depends on EXPERIMENTAL | ||
| 784 | depends on NETFILTER_TPROXY | ||
| 785 | depends on NETFILTER_XTABLES | ||
| 786 | depends on NETFILTER_ADVANCED | ||
| 787 | select NF_DEFRAG_IPV4 | ||
| 788 | help | ||
| 789 | This option adds a `socket' match, which can be used to match | ||
| 790 | packets for which a TCP or UDP socket lookup finds a valid socket. | ||
| 791 | It can be used in combination with the MARK target and policy | ||
| 792 | routing to implement full featured non-locally bound sockets. | ||
| 793 | |||
| 794 | To compile it as a module, choose M here. If unsure, say N. | ||
| 795 | |||
| 781 | config NETFILTER_XT_MATCH_STATE | 796 | config NETFILTER_XT_MATCH_STATE |
| 782 | tristate '"state" match support' | 797 | tristate '"state" match support' |
| 783 | depends on NETFILTER_XTABLES | 798 | depends on NETFILTER_XTABLES |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index fc8bbb48d383..1cdc3a13d01f 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
| @@ -81,6 +81,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_RATEEST) += xt_rateest.o | |||
| 81 | obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o | 81 | obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o |
| 82 | obj-$(CONFIG_NETFILTER_XT_MATCH_RECENT) += xt_recent.o | 82 | obj-$(CONFIG_NETFILTER_XT_MATCH_RECENT) += xt_recent.o |
| 83 | obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o | 83 | obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o |
| 84 | obj-$(CONFIG_NETFILTER_XT_MATCH_SOCKET) += xt_socket.o | ||
| 84 | obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o | 85 | obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o |
| 85 | obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o | 86 | obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o |
| 86 | obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o | 87 | obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o |
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c new file mode 100644 index 000000000000..ac9db17c7b9c --- /dev/null +++ b/net/netfilter/xt_socket.c | |||
| @@ -0,0 +1,192 @@ | |||
| 1 | /* | ||
| 2 | * Transparent proxy support for Linux/iptables | ||
| 3 | * | ||
| 4 | * Copyright (C) 2007-2008 BalaBit IT Ltd. | ||
| 5 | * Author: Krisztian Kovacs | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/skbuff.h> | ||
| 15 | #include <linux/netfilter/x_tables.h> | ||
| 16 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
| 17 | #include <net/tcp.h> | ||
| 18 | #include <net/udp.h> | ||
| 19 | #include <net/icmp.h> | ||
| 20 | #include <net/sock.h> | ||
| 21 | #include <net/inet_sock.h> | ||
| 22 | #include <net/netfilter/nf_tproxy_core.h> | ||
| 23 | #include <net/netfilter/ipv4/nf_defrag_ipv4.h> | ||
| 24 | |||
| 25 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | ||
| 26 | #define XT_SOCKET_HAVE_CONNTRACK 1 | ||
| 27 | #include <net/netfilter/nf_conntrack.h> | ||
| 28 | #endif | ||
| 29 | |||
| 30 | static int | ||
| 31 | extract_icmp_fields(const struct sk_buff *skb, | ||
| 32 | u8 *protocol, | ||
| 33 | __be32 *raddr, | ||
| 34 | __be32 *laddr, | ||
| 35 | __be16 *rport, | ||
| 36 | __be16 *lport) | ||
| 37 | { | ||
| 38 | unsigned int outside_hdrlen = ip_hdrlen(skb); | ||
| 39 | struct iphdr *inside_iph, _inside_iph; | ||
| 40 | struct icmphdr *icmph, _icmph; | ||
| 41 | __be16 *ports, _ports[2]; | ||
| 42 | |||
| 43 | icmph = skb_header_pointer(skb, outside_hdrlen, | ||
| 44 | sizeof(_icmph), &_icmph); | ||
| 45 | if (icmph == NULL) | ||
| 46 | return 1; | ||
| 47 | |||
| 48 | switch (icmph->type) { | ||
| 49 | case ICMP_DEST_UNREACH: | ||
| 50 | case ICMP_SOURCE_QUENCH: | ||
| 51 | case ICMP_REDIRECT: | ||
| 52 | case ICMP_TIME_EXCEEDED: | ||
| 53 | case ICMP_PARAMETERPROB: | ||
| 54 | break; | ||
| 55 | default: | ||
| 56 | return 1; | ||
| 57 | } | ||
| 58 | |||
| 59 | inside_iph = skb_header_pointer(skb, outside_hdrlen + | ||
| 60 | sizeof(struct icmphdr), | ||
| 61 | sizeof(_inside_iph), &_inside_iph); | ||
| 62 | if (inside_iph == NULL) | ||
| 63 | return 1; | ||
| 64 | |||
| 65 | if (inside_iph->protocol != IPPROTO_TCP && | ||
| 66 | inside_iph->protocol != IPPROTO_UDP) | ||
| 67 | return 1; | ||
| 68 | |||
| 69 | ports = skb_header_pointer(skb, outside_hdrlen + | ||
| 70 | sizeof(struct icmphdr) + | ||
| 71 | (inside_iph->ihl << 2), | ||
| 72 | sizeof(_ports), &_ports); | ||
| 73 | if (ports == NULL) | ||
| 74 | return 1; | ||
| 75 | |||
| 76 | /* the inside IP packet is the one quoted from our side, thus | ||
| 77 | * its saddr is the local address */ | ||
| 78 | *protocol = inside_iph->protocol; | ||
| 79 | *laddr = inside_iph->saddr; | ||
| 80 | *lport = ports[0]; | ||
| 81 | *raddr = inside_iph->daddr; | ||
| 82 | *rport = ports[1]; | ||
| 83 | |||
| 84 | return 0; | ||
| 85 | } | ||
| 86 | |||
| 87 | |||
| 88 | static bool | ||
| 89 | socket_mt(const struct sk_buff *skb, | ||
| 90 | const struct net_device *in, | ||
| 91 | const struct net_device *out, | ||
| 92 | const struct xt_match *match, | ||
| 93 | const void *matchinfo, | ||
| 94 | int offset, | ||
| 95 | unsigned int protoff, | ||
| 96 | bool *hotdrop) | ||
| 97 | { | ||
| 98 | const struct iphdr *iph = ip_hdr(skb); | ||
| 99 | struct udphdr _hdr, *hp = NULL; | ||
| 100 | struct sock *sk; | ||
| 101 | __be32 daddr, saddr; | ||
| 102 | __be16 dport, sport; | ||
| 103 | u8 protocol; | ||
| 104 | #ifdef XT_SOCKET_HAVE_CONNTRACK | ||
| 105 | struct nf_conn const *ct; | ||
| 106 | enum ip_conntrack_info ctinfo; | ||
| 107 | #endif | ||
| 108 | |||
| 109 | if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_TCP) { | ||
| 110 | hp = skb_header_pointer(skb, ip_hdrlen(skb), | ||
| 111 | sizeof(_hdr), &_hdr); | ||
| 112 | if (hp == NULL) | ||
| 113 | return false; | ||
| 114 | |||
| 115 | protocol = iph->protocol; | ||
| 116 | saddr = iph->saddr; | ||
| 117 | sport = hp->source; | ||
| 118 | daddr = iph->daddr; | ||
| 119 | dport = hp->dest; | ||
| 120 | |||
| 121 | } else if (iph->protocol == IPPROTO_ICMP) { | ||
| 122 | if (extract_icmp_fields(skb, &protocol, &saddr, &daddr, | ||
| 123 | &sport, &dport)) | ||
| 124 | return false; | ||
| 125 | } else { | ||
| 126 | return false; | ||
| 127 | } | ||
| 128 | |||
| 129 | #ifdef XT_SOCKET_HAVE_CONNTRACK | ||
| 130 | /* Do the lookup with the original socket address in case this is a | ||
| 131 | * reply packet of an established SNAT-ted connection. */ | ||
| 132 | |||
| 133 | ct = nf_ct_get(skb, &ctinfo); | ||
| 134 | if (ct && (ct != &nf_conntrack_untracked) && | ||
| 135 | ((iph->protocol != IPPROTO_ICMP && | ||
| 136 | ctinfo == IP_CT_IS_REPLY + IP_CT_ESTABLISHED) || | ||
| 137 | (iph->protocol == IPPROTO_ICMP && | ||
| 138 | ctinfo == IP_CT_IS_REPLY + IP_CT_RELATED)) && | ||
| 139 | (ct->status & IPS_SRC_NAT_DONE)) { | ||
| 140 | |||
| 141 | daddr = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; | ||
| 142 | dport = (iph->protocol == IPPROTO_TCP) ? | ||
| 143 | ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.tcp.port : | ||
| 144 | ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port; | ||
| 145 | } | ||
| 146 | #endif | ||
| 147 | |||
| 148 | sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), protocol, | ||
| 149 | saddr, daddr, sport, dport, in, false); | ||
| 150 | if (sk != NULL) { | ||
| 151 | bool wildcard = (inet_sk(sk)->rcv_saddr == 0); | ||
| 152 | |||
