PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/kernels/linux-2.6.16-gazineu/net/ipv6/netfilter/ip6t_REJECT.c

http://snake-os.googlecode.com/
C | 284 lines | 216 code | 39 blank | 29 comment | 38 complexity | fcacd535efdd141c97029fd45709338d MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, 0BSD, BSD-3-Clause, GPL-3.0, AGPL-1.0, CC-BY-SA-3.0
  1. /*
  2. * IP6 tables REJECT target module
  3. * Linux INET6 implementation
  4. *
  5. * Copyright (C)2003 USAGI/WIDE Project
  6. *
  7. * Authors:
  8. * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
  9. *
  10. * Based on net/ipv4/netfilter/ipt_REJECT.c
  11. *
  12. * This program is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU General Public License
  14. * as published by the Free Software Foundation; either version
  15. * 2 of the License, or (at your option) any later version.
  16. */
  17. #include <linux/config.h>
  18. #include <linux/module.h>
  19. #include <linux/skbuff.h>
  20. #include <linux/icmpv6.h>
  21. #include <linux/netdevice.h>
  22. #include <net/ipv6.h>
  23. #include <net/tcp.h>
  24. #include <net/icmp.h>
  25. #include <net/ip6_checksum.h>
  26. #include <net/ip6_fib.h>
  27. #include <net/ip6_route.h>
  28. #include <net/flow.h>
  29. #include <linux/netfilter_ipv6/ip6_tables.h>
  30. #include <linux/netfilter_ipv6/ip6t_REJECT.h>
  31. MODULE_AUTHOR("Yasuyuki KOZAKAI <yasuyuki.kozakai@toshiba.co.jp>");
  32. MODULE_DESCRIPTION("IP6 tables REJECT target module");
  33. MODULE_LICENSE("GPL");
  34. #if 0
  35. #define DEBUGP printk
  36. #else
  37. #define DEBUGP(format, args...)
  38. #endif
  39. /* Send RST reply */
  40. static void send_reset(struct sk_buff *oldskb)
  41. {
  42. struct sk_buff *nskb;
  43. struct tcphdr otcph, *tcph;
  44. unsigned int otcplen, hh_len;
  45. int tcphoff, needs_ack;
  46. struct ipv6hdr *oip6h = oldskb->nh.ipv6h, *ip6h;
  47. struct dst_entry *dst = NULL;
  48. u8 proto;
  49. struct flowi fl;
  50. if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
  51. (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) {
  52. DEBUGP("ip6t_REJECT: addr is not unicast.\n");
  53. return;
  54. }
  55. proto = oip6h->nexthdr;
  56. tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto);
  57. if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
  58. DEBUGP("ip6t_REJECT: Can't get TCP header.\n");
  59. return;
  60. }
  61. otcplen = oldskb->len - tcphoff;
  62. /* IP header checks: fragment, too short. */
  63. if ((proto != IPPROTO_TCP) || (otcplen < sizeof(struct tcphdr))) {
  64. DEBUGP("ip6t_REJECT: proto(%d) != IPPROTO_TCP, or too short. otcplen = %d\n",
  65. proto, otcplen);
  66. return;
  67. }
  68. if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr)))
  69. BUG();
  70. /* No RST for RST. */
  71. if (otcph.rst) {
  72. DEBUGP("ip6t_REJECT: RST is set\n");
  73. return;
  74. }
  75. /* Check checksum. */
  76. if (csum_ipv6_magic(&oip6h->saddr, &oip6h->daddr, otcplen, IPPROTO_TCP,
  77. skb_checksum(oldskb, tcphoff, otcplen, 0))) {
  78. DEBUGP("ip6t_REJECT: TCP checksum is invalid\n");
  79. return;
  80. }
  81. memset(&fl, 0, sizeof(fl));
  82. fl.proto = IPPROTO_TCP;
  83. ipv6_addr_copy(&fl.fl6_src, &oip6h->daddr);
  84. ipv6_addr_copy(&fl.fl6_dst, &oip6h->saddr);
  85. fl.fl_ip_sport = otcph.dest;
  86. fl.fl_ip_dport = otcph.source;
  87. dst = ip6_route_output(NULL, &fl);
  88. if (dst == NULL)
  89. return;
  90. if (dst->error || xfrm_lookup(&dst, &fl, NULL, 0))
  91. return;
  92. hh_len = (dst->dev->hard_header_len + 15)&~15;
  93. nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr)
  94. + sizeof(struct tcphdr) + dst->trailer_len,
  95. GFP_ATOMIC);
  96. if (!nskb) {
  97. if (net_ratelimit())
  98. printk("ip6t_REJECT: Can't alloc skb\n");
  99. dst_release(dst);
  100. return;
  101. }
  102. nskb->dst = dst;
  103. skb_reserve(nskb, hh_len + dst->header_len);
  104. ip6h = nskb->nh.ipv6h = (struct ipv6hdr *)
  105. skb_put(nskb, sizeof(struct ipv6hdr));
  106. ip6h->version = 6;
  107. ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT);
  108. ip6h->nexthdr = IPPROTO_TCP;
  109. ip6h->payload_len = htons(sizeof(struct tcphdr));
  110. ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr);
  111. ipv6_addr_copy(&ip6h->daddr, &oip6h->saddr);
  112. tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
  113. /* Truncate to length (no data) */
  114. tcph->doff = sizeof(struct tcphdr)/4;
  115. tcph->source = otcph.dest;
  116. tcph->dest = otcph.source;
  117. if (otcph.ack) {
  118. needs_ack = 0;
  119. tcph->seq = otcph.ack_seq;
  120. tcph->ack_seq = 0;
  121. } else {
  122. needs_ack = 1;
  123. tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin
  124. + otcplen - (otcph.doff<<2));
  125. tcph->seq = 0;
  126. }
  127. /* Reset flags */
  128. ((u_int8_t *)tcph)[13] = 0;
  129. tcph->rst = 1;
  130. tcph->ack = needs_ack;
  131. tcph->window = 0;
  132. tcph->urg_ptr = 0;
  133. tcph->check = 0;
  134. /* Adjust TCP checksum */
  135. tcph->check = csum_ipv6_magic(&nskb->nh.ipv6h->saddr,
  136. &nskb->nh.ipv6h->daddr,
  137. sizeof(struct tcphdr), IPPROTO_TCP,
  138. csum_partial((char *)tcph,
  139. sizeof(struct tcphdr), 0));
  140. nf_ct_attach(nskb, oldskb);
  141. NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
  142. dst_output);
  143. }
  144. static inline void
  145. send_unreach(struct sk_buff *skb_in, unsigned char code, unsigned int hooknum)
  146. {
  147. if (hooknum == NF_IP6_LOCAL_OUT && skb_in->dev == NULL)
  148. skb_in->dev = &loopback_dev;
  149. icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0, NULL);
  150. }
  151. static unsigned int reject6_target(struct sk_buff **pskb,
  152. const struct net_device *in,
  153. const struct net_device *out,
  154. unsigned int hooknum,
  155. const void *targinfo,
  156. void *userinfo)
  157. {
  158. const struct ip6t_reject_info *reject = targinfo;
  159. DEBUGP(KERN_DEBUG "%s: medium point\n", __FUNCTION__);
  160. /* WARNING: This code causes reentry within ip6tables.
  161. This means that the ip6tables jump stack is now crap. We
  162. must return an absolute verdict. --RR */
  163. switch (reject->with) {
  164. case IP6T_ICMP6_NO_ROUTE:
  165. send_unreach(*pskb, ICMPV6_NOROUTE, hooknum);
  166. break;
  167. case IP6T_ICMP6_ADM_PROHIBITED:
  168. send_unreach(*pskb, ICMPV6_ADM_PROHIBITED, hooknum);
  169. break;
  170. case IP6T_ICMP6_NOT_NEIGHBOUR:
  171. send_unreach(*pskb, ICMPV6_NOT_NEIGHBOUR, hooknum);
  172. break;
  173. case IP6T_ICMP6_ADDR_UNREACH:
  174. send_unreach(*pskb, ICMPV6_ADDR_UNREACH, hooknum);
  175. break;
  176. case IP6T_ICMP6_PORT_UNREACH:
  177. send_unreach(*pskb, ICMPV6_PORT_UNREACH, hooknum);
  178. break;
  179. case IP6T_ICMP6_ECHOREPLY:
  180. /* Do nothing */
  181. break;
  182. case IP6T_TCP_RESET:
  183. send_reset(*pskb);
  184. break;
  185. default:
  186. if (net_ratelimit())
  187. printk(KERN_WARNING "ip6t_REJECT: case %u not handled yet\n", reject->with);
  188. break;
  189. }
  190. return NF_DROP;
  191. }
  192. static int check(const char *tablename,
  193. const void *entry,
  194. void *targinfo,
  195. unsigned int targinfosize,
  196. unsigned int hook_mask)
  197. {
  198. const struct ip6t_reject_info *rejinfo = targinfo;
  199. const struct ip6t_entry *e = entry;
  200. if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) {
  201. DEBUGP("ip6t_REJECT: targinfosize %u != 0\n", targinfosize);
  202. return 0;
  203. }
  204. /* Only allow these for packet filtering. */
  205. if (strcmp(tablename, "filter") != 0) {
  206. DEBUGP("ip6t_REJECT: bad table `%s'.\n", tablename);
  207. return 0;
  208. }
  209. if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN)
  210. | (1 << NF_IP6_FORWARD)
  211. | (1 << NF_IP6_LOCAL_OUT))) != 0) {
  212. DEBUGP("ip6t_REJECT: bad hook mask %X\n", hook_mask);
  213. return 0;
  214. }
  215. if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
  216. printk("ip6t_REJECT: ECHOREPLY is not supported.\n");
  217. return 0;
  218. } else if (rejinfo->with == IP6T_TCP_RESET) {
  219. /* Must specify that it's a TCP packet */
  220. if (e->ipv6.proto != IPPROTO_TCP
  221. || (e->ipv6.invflags & IP6T_INV_PROTO)) {
  222. DEBUGP("ip6t_REJECT: TCP_RESET illegal for non-tcp\n");
  223. return 0;
  224. }
  225. }
  226. return 1;
  227. }
  228. static struct ip6t_target ip6t_reject_reg = {
  229. .name = "REJECT",
  230. .target = reject6_target,
  231. .checkentry = check,
  232. .me = THIS_MODULE
  233. };
  234. static int __init init(void)
  235. {
  236. if (ip6t_register_target(&ip6t_reject_reg))
  237. return -EINVAL;
  238. return 0;
  239. }
  240. static void __exit fini(void)
  241. {
  242. ip6t_unregister_target(&ip6t_reject_reg);
  243. }
  244. module_init(init);
  245. module_exit(fini);