xt_socket.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  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. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  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. #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
  25. #define XT_SOCKET_HAVE_IPV6 1
  26. #include <linux/netfilter_ipv6/ip6_tables.h>
  27. #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
  28. #endif
  29. #include <linux/netfilter/xt_socket.h>
  30. #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
  31. #define XT_SOCKET_HAVE_CONNTRACK 1
  32. #include <net/netfilter/nf_conntrack.h>
  33. #endif
  34. void
  35. xt_socket_put_sk(struct sock *sk)
  36. {
  37. if (sk->sk_state == TCP_TIME_WAIT)
  38. inet_twsk_put(inet_twsk(sk));
  39. else
  40. sock_put(sk);
  41. }
  42. EXPORT_SYMBOL(xt_socket_put_sk);
  43. static int
  44. extract_icmp4_fields(const struct sk_buff *skb,
  45. u8 *protocol,
  46. __be32 *raddr,
  47. __be32 *laddr,
  48. __be16 *rport,
  49. __be16 *lport)
  50. {
  51. unsigned int outside_hdrlen = ip_hdrlen(skb);
  52. struct iphdr *inside_iph, _inside_iph;
  53. struct icmphdr *icmph, _icmph;
  54. __be16 *ports, _ports[2];
  55. icmph = skb_header_pointer(skb, outside_hdrlen,
  56. sizeof(_icmph), &_icmph);
  57. if (icmph == NULL)
  58. return 1;
  59. switch (icmph->type) {
  60. case ICMP_DEST_UNREACH:
  61. case ICMP_SOURCE_QUENCH:
  62. case ICMP_REDIRECT:
  63. case ICMP_TIME_EXCEEDED:
  64. case ICMP_PARAMETERPROB:
  65. break;
  66. default:
  67. return 1;
  68. }
  69. inside_iph = skb_header_pointer(skb, outside_hdrlen +
  70. sizeof(struct icmphdr),
  71. sizeof(_inside_iph), &_inside_iph);
  72. if (inside_iph == NULL)
  73. return 1;
  74. if (inside_iph->protocol != IPPROTO_TCP &&
  75. inside_iph->protocol != IPPROTO_UDP)
  76. return 1;
  77. ports = skb_header_pointer(skb, outside_hdrlen +
  78. sizeof(struct icmphdr) +
  79. (inside_iph->ihl << 2),
  80. sizeof(_ports), &_ports);
  81. if (ports == NULL)
  82. return 1;
  83. /* the inside IP packet is the one quoted from our side, thus
  84. * its saddr is the local address */
  85. *protocol = inside_iph->protocol;
  86. *laddr = inside_iph->saddr;
  87. *lport = ports[0];
  88. *raddr = inside_iph->daddr;
  89. *rport = ports[1];
  90. return 0;
  91. }
  92. struct sock*
  93. xt_socket_get4_sk(const struct sk_buff *skb, struct xt_action_param *par)
  94. {
  95. const struct iphdr *iph = ip_hdr(skb);
  96. struct udphdr _hdr, *hp = NULL;
  97. struct sock *sk;
  98. __be32 daddr, saddr;
  99. __be16 dport, sport;
  100. u8 protocol;
  101. #ifdef XT_SOCKET_HAVE_CONNTRACK
  102. struct nf_conn const *ct;
  103. enum ip_conntrack_info ctinfo;
  104. #endif
  105. if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_TCP) {
  106. hp = skb_header_pointer(skb, ip_hdrlen(skb),
  107. sizeof(_hdr), &_hdr);
  108. if (hp == NULL)
  109. return NULL;
  110. protocol = iph->protocol;
  111. saddr = iph->saddr;
  112. sport = hp->source;
  113. daddr = iph->daddr;
  114. dport = hp->dest;
  115. } else if (iph->protocol == IPPROTO_ICMP) {
  116. if (extract_icmp4_fields(skb, &protocol, &saddr, &daddr,
  117. &sport, &dport))
  118. return NULL;
  119. } else {
  120. return NULL;
  121. }
  122. #ifdef XT_SOCKET_HAVE_CONNTRACK
  123. /* Do the lookup with the original socket address in case this is a
  124. * reply packet of an established SNAT-ted connection. */
  125. ct = nf_ct_get(skb, &ctinfo);
  126. if (ct && !nf_ct_is_untracked(ct) &&
  127. ((iph->protocol != IPPROTO_ICMP &&
  128. ctinfo == IP_CT_ESTABLISHED_REPLY) ||
  129. (iph->protocol == IPPROTO_ICMP &&
  130. ctinfo == IP_CT_RELATED_REPLY)) &&
  131. (ct->status & IPS_SRC_NAT_DONE)) {
  132. daddr = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
  133. dport = (iph->protocol == IPPROTO_TCP) ?
  134. ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.tcp.port :
  135. ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port;
  136. }
  137. #endif
  138. sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), protocol,
  139. saddr, daddr, sport, dport, par->in, NFT_LOOKUP_ANY);
  140. pr_debug("proto %hhu %pI4:%hu -> %pI4:%hu (orig %pI4:%hu) sock %p\n",
  141. protocol, &saddr, ntohs(sport),
  142. &daddr, ntohs(dport),
  143. &iph->daddr, hp ? ntohs(hp->dest) : 0, sk);
  144. return sk;
  145. }
  146. EXPORT_SYMBOL(xt_socket_get4_sk);
  147. static bool
  148. socket_match(const struct sk_buff *skb, struct xt_action_param *par,
  149. const struct xt_socket_mtinfo1 *info)
  150. {
  151. struct sock *sk;
  152. sk = xt_socket_get4_sk(skb, par);
  153. if (sk != NULL) {
  154. bool wildcard;
  155. bool transparent = true;
  156. /* Ignore sockets listening on INADDR_ANY */
  157. wildcard = (sk->sk_state != TCP_TIME_WAIT &&
  158. inet_sk(sk)->inet_rcv_saddr == 0);
  159. /* Ignore non-transparent sockets,
  160. if XT_SOCKET_TRANSPARENT is used */
  161. if (info && info->flags & XT_SOCKET_TRANSPARENT)
  162. transparent = ((sk->sk_state != TCP_TIME_WAIT &&
  163. inet_sk(sk)->transparent) ||
  164. (sk->sk_state == TCP_TIME_WAIT &&
  165. inet_twsk(sk)->tw_transparent));
  166. xt_socket_put_sk(sk);
  167. if (wildcard || !transparent)
  168. sk = NULL;
  169. }
  170. return (sk != NULL);
  171. }
  172. static bool
  173. socket_mt4_v0(const struct sk_buff *skb, struct xt_action_param *par)
  174. {
  175. return socket_match(skb, par, NULL);
  176. }
  177. static bool
  178. socket_mt4_v1(const struct sk_buff *skb, struct xt_action_param *par)
  179. {
  180. return socket_match(skb, par, par->matchinfo);
  181. }
  182. #ifdef XT_SOCKET_HAVE_IPV6
  183. static int
  184. extract_icmp6_fields(const struct sk_buff *skb,
  185. unsigned int outside_hdrlen,
  186. int *protocol,
  187. struct in6_addr **raddr,
  188. struct in6_addr **laddr,
  189. __be16 *rport,
  190. __be16 *lport)
  191. {
  192. struct ipv6hdr *inside_iph, _inside_iph;
  193. struct icmp6hdr *icmph, _icmph;
  194. __be16 *ports, _ports[2];
  195. u8 inside_nexthdr;
  196. int inside_hdrlen;
  197. icmph = skb_header_pointer(skb, outside_hdrlen,
  198. sizeof(_icmph), &_icmph);
  199. if (icmph == NULL)
  200. return 1;
  201. if (icmph->icmp6_type & ICMPV6_INFOMSG_MASK)
  202. return 1;
  203. inside_iph = skb_header_pointer(skb, outside_hdrlen + sizeof(_icmph), sizeof(_inside_iph), &_inside_iph);
  204. if (inside_iph == NULL)
  205. return 1;
  206. inside_nexthdr = inside_iph->nexthdr;
  207. inside_hdrlen = ipv6_skip_exthdr(skb, outside_hdrlen + sizeof(_icmph) + sizeof(_inside_iph), &inside_nexthdr);
  208. if (inside_hdrlen < 0)
  209. return 1; /* hjm: Packet has no/incomplete transport layer headers. */
  210. if (inside_nexthdr != IPPROTO_TCP &&
  211. inside_nexthdr != IPPROTO_UDP)
  212. return 1;
  213. ports = skb_header_pointer(skb, inside_hdrlen,
  214. sizeof(_ports), &_ports);
  215. if (ports == NULL)
  216. return 1;
  217. /* the inside IP packet is the one quoted from our side, thus
  218. * its saddr is the local address */
  219. *protocol = inside_nexthdr;
  220. *laddr = &inside_iph->saddr;
  221. *lport = ports[0];
  222. *raddr = &inside_iph->daddr;
  223. *rport = ports[1];
  224. return 0;
  225. }
  226. struct sock*
  227. xt_socket_get6_sk(const struct sk_buff *skb, struct xt_action_param *par)
  228. {
  229. struct ipv6hdr *iph = ipv6_hdr(skb);
  230. struct udphdr _hdr, *hp = NULL;
  231. struct sock *sk;
  232. struct in6_addr *daddr, *saddr;
  233. __be16 dport, sport;
  234. int thoff, tproto;
  235. tproto = ipv6_find_hdr(skb, &thoff, -1, NULL);
  236. if (tproto < 0) {
  237. pr_debug("unable to find transport header in IPv6 packet, dropping\n");
  238. return NF_DROP;
  239. }
  240. if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP) {
  241. hp = skb_header_pointer(skb, thoff,
  242. sizeof(_hdr), &_hdr);
  243. if (hp == NULL)
  244. return NULL;
  245. saddr = &iph->saddr;
  246. sport = hp->source;
  247. daddr = &iph->daddr;
  248. dport = hp->dest;
  249. } else if (tproto == IPPROTO_ICMPV6) {
  250. if (extract_icmp6_fields(skb, thoff, &tproto, &saddr, &daddr,
  251. &sport, &dport))
  252. return NULL;
  253. } else {
  254. return NULL;
  255. }
  256. sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
  257. saddr, daddr, sport, dport, par->in, NFT_LOOKUP_ANY);
  258. pr_debug("proto %hhd %pI6:%hu -> %pI6:%hu "
  259. "(orig %pI6:%hu) sock %p\n",
  260. tproto, saddr, ntohs(sport),
  261. daddr, ntohs(dport),
  262. &iph->daddr, hp ? ntohs(hp->dest) : 0, sk);
  263. return sk;
  264. }
  265. EXPORT_SYMBOL(xt_socket_get6_sk);
  266. static bool
  267. socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par)
  268. {
  269. struct sock *sk;
  270. const struct xt_socket_mtinfo1 *info;
  271. info = (struct xt_socket_mtinfo1 *) par->matchinfo;
  272. sk = xt_socket_get6_sk(skb, par);
  273. if (sk != NULL) {
  274. bool wildcard;
  275. bool transparent = true;
  276. /* Ignore sockets listening on INADDR_ANY */
  277. wildcard = (sk->sk_state != TCP_TIME_WAIT &&
  278. ipv6_addr_any(&inet6_sk(sk)->rcv_saddr));
  279. /* Ignore non-transparent sockets,
  280. if XT_SOCKET_TRANSPARENT is used */
  281. if (info && info->flags & XT_SOCKET_TRANSPARENT)
  282. transparent = ((sk->sk_state != TCP_TIME_WAIT &&
  283. inet_sk(sk)->transparent) ||
  284. (sk->sk_state == TCP_TIME_WAIT &&
  285. inet_twsk(sk)->tw_transparent));
  286. xt_socket_put_sk(sk);
  287. if (wildcard || !transparent)
  288. sk = NULL;
  289. }
  290. return (sk != NULL);
  291. }
  292. #endif
  293. static struct xt_match socket_mt_reg[] __read_mostly = {
  294. {
  295. .name = "socket",
  296. .revision = 0,
  297. .family = NFPROTO_IPV4,
  298. .match = socket_mt4_v0,
  299. .hooks = (1 << NF_INET_PRE_ROUTING) |
  300. (1 << NF_INET_LOCAL_IN),
  301. .me = THIS_MODULE,
  302. },
  303. {
  304. .name = "socket",
  305. .revision = 1,
  306. .family = NFPROTO_IPV4,
  307. .match = socket_mt4_v1,
  308. .matchsize = sizeof(struct xt_socket_mtinfo1),
  309. .hooks = (1 << NF_INET_PRE_ROUTING) |
  310. (1 << NF_INET_LOCAL_IN),
  311. .me = THIS_MODULE,
  312. },
  313. #ifdef XT_SOCKET_HAVE_IPV6
  314. {
  315. .name = "socket",
  316. .revision = 1,
  317. .family = NFPROTO_IPV6,
  318. .match = socket_mt6_v1,
  319. .matchsize = sizeof(struct xt_socket_mtinfo1),
  320. .hooks = (1 << NF_INET_PRE_ROUTING) |
  321. (1 << NF_INET_LOCAL_IN),
  322. .me = THIS_MODULE,
  323. },
  324. #endif
  325. };
  326. static int __init socket_mt_init(void)
  327. {
  328. nf_defrag_ipv4_enable();
  329. #ifdef XT_SOCKET_HAVE_IPV6
  330. nf_defrag_ipv6_enable();
  331. #endif
  332. return xt_register_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg));
  333. }
  334. static void __exit socket_mt_exit(void)
  335. {
  336. xt_unregister_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg));
  337. }
  338. module_init(socket_mt_init);
  339. module_exit(socket_mt_exit);
  340. MODULE_LICENSE("GPL");
  341. MODULE_AUTHOR("Krisztian Kovacs, Balazs Scheidler");
  342. MODULE_DESCRIPTION("x_tables socket match module");
  343. MODULE_ALIAS("ipt_socket");
  344. MODULE_ALIAS("ip6t_socket");