1414#include <linux/skbuff.h>
1515#include <linux/netfilter/x_tables.h>
1616#include <linux/netfilter_ipv4/ip_tables.h>
17+ #include <linux/netfilter_ipv6/ip6_tables.h>
1718#include <net/tcp.h>
1819#include <net/udp.h>
1920#include <net/icmp.h>
2021#include <net/sock.h>
2122#include <net/inet_sock.h>
2223#include <net/netfilter/nf_tproxy_core.h>
2324#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
25+ #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
2426
2527#include <linux/netfilter/xt_socket.h>
2628
3032#endif
3133
3234static int
33- extract_icmp_fields (const struct sk_buff * skb ,
35+ extract_icmp4_fields (const struct sk_buff * skb ,
3436 u8 * protocol ,
3537 __be32 * raddr ,
3638 __be32 * laddr ,
@@ -86,7 +88,6 @@ extract_icmp_fields(const struct sk_buff *skb,
8688 return 0 ;
8789}
8890
89-
9091static bool
9192socket_match (const struct sk_buff * skb , struct xt_action_param * par ,
9293 const struct xt_socket_mtinfo1 * info )
@@ -115,7 +116,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
115116 dport = hp -> dest ;
116117
117118 } else if (iph -> protocol == IPPROTO_ICMP ) {
118- if (extract_icmp_fields (skb , & protocol , & saddr , & daddr ,
119+ if (extract_icmp4_fields (skb , & protocol , & saddr , & daddr ,
119120 & sport , & dport ))
120121 return false;
121122 } else {
@@ -165,32 +166,157 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
165166 sk = NULL ;
166167 }
167168
168- pr_debug ("proto %u %08x:%u -> %08x:%u (orig %08x:%u ) sock %p\n" ,
169- protocol , ntohl ( saddr ) , ntohs (sport ),
170- ntohl ( daddr ) , ntohs (dport ),
171- ntohl ( iph -> daddr ) , hp ? ntohs (hp -> dest ) : 0 , sk );
169+ pr_debug ("proto %hhu %pI4:%hu -> %pI4:%hu (orig %pI4:%hu ) sock %p\n" ,
170+ protocol , & saddr , ntohs (sport ),
171+ & daddr , ntohs (dport ),
172+ & iph -> daddr , hp ? ntohs (hp -> dest ) : 0 , sk );
172173
173174 return (sk != NULL );
174175}
175176
176177static bool
177- socket_mt_v0 (const struct sk_buff * skb , struct xt_action_param * par )
178+ socket_mt4_v0 (const struct sk_buff * skb , struct xt_action_param * par )
178179{
179180 return socket_match (skb , par , NULL );
180181}
181182
182183static bool
183- socket_mt_v1 (const struct sk_buff * skb , struct xt_action_param * par )
184+ socket_mt4_v1 (const struct sk_buff * skb , struct xt_action_param * par )
184185{
185186 return socket_match (skb , par , par -> matchinfo );
186187}
187188
189+ #if defined(CONFIG_IPV6 ) || defined(CONFIG_IPV6_MODULE )
190+
191+ static int
192+ extract_icmp6_fields (const struct sk_buff * skb ,
193+ unsigned int outside_hdrlen ,
194+ u8 * protocol ,
195+ struct in6_addr * * raddr ,
196+ struct in6_addr * * laddr ,
197+ __be16 * rport ,
198+ __be16 * lport )
199+ {
200+ struct ipv6hdr * inside_iph , _inside_iph ;
201+ struct icmp6hdr * icmph , _icmph ;
202+ __be16 * ports , _ports [2 ];
203+ u8 inside_nexthdr ;
204+ int inside_hdrlen ;
205+
206+ icmph = skb_header_pointer (skb , outside_hdrlen ,
207+ sizeof (_icmph ), & _icmph );
208+ if (icmph == NULL )
209+ return 1 ;
210+
211+ if (icmph -> icmp6_type & ICMPV6_INFOMSG_MASK )
212+ return 1 ;
213+
214+ inside_iph = skb_header_pointer (skb , outside_hdrlen + sizeof (_icmph ), sizeof (_inside_iph ), & _inside_iph );
215+ if (inside_iph == NULL )
216+ return 1 ;
217+ inside_nexthdr = inside_iph -> nexthdr ;
218+
219+ inside_hdrlen = ipv6_skip_exthdr (skb , outside_hdrlen + sizeof (_icmph ) + sizeof (_inside_iph ), & inside_nexthdr );
220+ if (inside_hdrlen < 0 )
221+ return 1 ; /* hjm: Packet has no/incomplete transport layer headers. */
222+
223+ if (inside_nexthdr != IPPROTO_TCP &&
224+ inside_nexthdr != IPPROTO_UDP )
225+ return 1 ;
226+
227+ ports = skb_header_pointer (skb , inside_hdrlen ,
228+ sizeof (_ports ), & _ports );
229+ if (ports == NULL )
230+ return 1 ;
231+
232+ /* the inside IP packet is the one quoted from our side, thus
233+ * its saddr is the local address */
234+ * protocol = inside_nexthdr ;
235+ * laddr = & inside_iph -> saddr ;
236+ * lport = ports [0 ];
237+ * raddr = & inside_iph -> daddr ;
238+ * rport = ports [1 ];
239+
240+ return 0 ;
241+ }
242+
243+ static bool
244+ socket_mt6_v1 (const struct sk_buff * skb , struct xt_action_param * par )
245+ {
246+ struct ipv6hdr * iph = ipv6_hdr (skb );
247+ struct udphdr _hdr , * hp = NULL ;
248+ struct sock * sk ;
249+ struct in6_addr * daddr , * saddr ;
250+ __be16 dport , sport ;
251+ int thoff ;
252+ u8 tproto ;
253+ const struct xt_socket_mtinfo1 * info = (struct xt_socket_mtinfo1 * ) par -> matchinfo ;
254+
255+ tproto = ipv6_find_hdr (skb , & thoff , -1 , NULL );
256+ if (tproto < 0 ) {
257+ pr_debug ("unable to find transport header in IPv6 packet, dropping\n" );
258+ return NF_DROP ;
259+ }
260+
261+ if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP ) {
262+ hp = skb_header_pointer (skb , thoff ,
263+ sizeof (_hdr ), & _hdr );
264+ if (hp == NULL )
265+ return false;
266+
267+ saddr = & iph -> saddr ;
268+ sport = hp -> source ;
269+ daddr = & iph -> daddr ;
270+ dport = hp -> dest ;
271+
272+ } else if (tproto == IPPROTO_ICMPV6 ) {
273+ if (extract_icmp6_fields (skb , thoff , & tproto , & saddr , & daddr ,
274+ & sport , & dport ))
275+ return false;
276+ } else {
277+ return false;
278+ }
279+
280+ sk = nf_tproxy_get_sock_v6 (dev_net (skb -> dev ), tproto ,
281+ saddr , daddr , sport , dport , par -> in , NFT_LOOKUP_ANY );
282+ if (sk != NULL ) {
283+ bool wildcard ;
284+ bool transparent = true;
285+
286+ /* Ignore sockets listening on INADDR_ANY */
287+ wildcard = (sk -> sk_state != TCP_TIME_WAIT &&
288+ ipv6_addr_any (& inet6_sk (sk )-> rcv_saddr ));
289+
290+ /* Ignore non-transparent sockets,
291+ if XT_SOCKET_TRANSPARENT is used */
292+ if (info && info -> flags & XT_SOCKET_TRANSPARENT )
293+ transparent = ((sk -> sk_state != TCP_TIME_WAIT &&
294+ inet_sk (sk )-> transparent ) ||
295+ (sk -> sk_state == TCP_TIME_WAIT &&
296+ inet_twsk (sk )-> tw_transparent ));
297+
298+ nf_tproxy_put_sock (sk );
299+
300+ if (wildcard || !transparent )
301+ sk = NULL ;
302+ }
303+
304+ pr_debug ("proto %hhu %pI6:%hu -> %pI6:%hu "
305+ "(orig %pI6:%hu) sock %p\n" ,
306+ tproto , saddr , ntohs (sport ),
307+ daddr , ntohs (dport ),
308+ & iph -> daddr , hp ? ntohs (hp -> dest ) : 0 , sk );
309+
310+ return (sk != NULL );
311+ }
312+ #endif
313+
188314static struct xt_match socket_mt_reg [] __read_mostly = {
189315 {
190316 .name = "socket" ,
191317 .revision = 0 ,
192318 .family = NFPROTO_IPV4 ,
193- .match = socket_mt_v0 ,
319+ .match = socket_mt4_v0 ,
194320 .hooks = (1 << NF_INET_PRE_ROUTING ) |
195321 (1 << NF_INET_LOCAL_IN ),
196322 .me = THIS_MODULE ,
@@ -199,17 +325,33 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
199325 .name = "socket" ,
200326 .revision = 1 ,
201327 .family = NFPROTO_IPV4 ,
202- .match = socket_mt_v1 ,
328+ .match = socket_mt4_v1 ,
203329 .matchsize = sizeof (struct xt_socket_mtinfo1 ),
204330 .hooks = (1 << NF_INET_PRE_ROUTING ) |
205331 (1 << NF_INET_LOCAL_IN ),
206332 .me = THIS_MODULE ,
207333 },
334+ #if defined(CONFIG_IPV6 ) || defined (CONFIG_IPV6_MODULE )
335+ {
336+ .name = "socket" ,
337+ .revision = 1 ,
338+ .family = NFPROTO_IPV6 ,
339+ .match = socket_mt6_v1 ,
340+ .matchsize = sizeof (struct xt_socket_mtinfo1 ),
341+ .hooks = (1 << NF_INET_PRE_ROUTING ) |
342+ (1 << NF_INET_LOCAL_IN ),
343+ .me = THIS_MODULE ,
344+ },
345+ #endif
208346};
209347
210348static int __init socket_mt_init (void )
211349{
212350 nf_defrag_ipv4_enable ();
351+ #if defined(CONFIG_IPV6 ) || defined(CONFIG_IPV6_MODULE )
352+ nf_defrag_ipv6_enable ();
353+ #endif
354+
213355 return xt_register_matches (socket_mt_reg , ARRAY_SIZE (socket_mt_reg ));
214356}
215357
@@ -225,3 +367,4 @@ MODULE_LICENSE("GPL");
225367MODULE_AUTHOR ("Krisztian Kovacs, Balazs Scheidler" );
226368MODULE_DESCRIPTION ("x_tables socket match module" );
227369MODULE_ALIAS ("ipt_socket" );
370+ MODULE_ALIAS ("ip6t_socket" );
0 commit comments