nf_nat_snmp_basic_main.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * nf_nat_snmp_basic.c
  4. *
  5. * Basic SNMP Application Layer Gateway
  6. *
  7. * This IP NAT module is intended for use with SNMP network
  8. * discovery and monitoring applications where target networks use
  9. * conflicting private address realms.
  10. *
  11. * Static NAT is used to remap the networks from the view of the network
  12. * management system at the IP layer, and this module remaps some application
  13. * layer addresses to match.
  14. *
  15. * The simplest form of ALG is performed, where only tagged IP addresses
  16. * are modified. The module does not need to be MIB aware and only scans
  17. * messages at the ASN.1/BER level.
  18. *
  19. * Currently, only SNMPv1 and SNMPv2 are supported.
  20. *
  21. * More information on ALG and associated issues can be found in
  22. * RFC 2962
  23. *
  24. * The ASB.1/BER parsing code is derived from the gxsnmp package by Gregory
  25. * McLean & Jochen Friedrich, stripped down for use in the kernel.
  26. *
  27. * Copyright (c) 2000 RP Internet (www.rpi.net.au).
  28. *
  29. * Author: James Morris <jmorris@intercode.com.au>
  30. *
  31. * Copyright (c) 2006-2010 Patrick McHardy <kaber@trash.net>
  32. */
  33. #include <linux/module.h>
  34. #include <linux/moduleparam.h>
  35. #include <linux/types.h>
  36. #include <linux/kernel.h>
  37. #include <linux/in.h>
  38. #include <linux/ip.h>
  39. #include <linux/udp.h>
  40. #include <net/checksum.h>
  41. #include <net/udp.h>
  42. #include <net/netfilter/nf_nat.h>
  43. #include <net/netfilter/nf_conntrack_expect.h>
  44. #include <net/netfilter/nf_conntrack_helper.h>
  45. #include <linux/netfilter/nf_conntrack_snmp.h>
  46. #include "nf_nat_snmp_basic.asn1.h"
  47. MODULE_LICENSE("GPL");
  48. MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
  49. MODULE_DESCRIPTION("Basic SNMP Application Layer Gateway");
  50. MODULE_ALIAS("ip_nat_snmp_basic");
  51. MODULE_ALIAS_NFCT_HELPER("snmp_trap");
  52. #define SNMP_PORT 161
  53. #define SNMP_TRAP_PORT 162
  54. static DEFINE_SPINLOCK(snmp_lock);
  55. struct snmp_ctx {
  56. unsigned char *begin;
  57. __sum16 *check;
  58. __be32 from;
  59. __be32 to;
  60. };
  61. static void fast_csum(struct snmp_ctx *ctx, unsigned char offset)
  62. {
  63. unsigned char s[12] = {0,};
  64. int size;
  65. if (offset & 1) {
  66. memcpy(&s[1], &ctx->from, 4);
  67. memcpy(&s[7], &ctx->to, 4);
  68. s[0] = ~0;
  69. s[1] = ~s[1];
  70. s[2] = ~s[2];
  71. s[3] = ~s[3];
  72. s[4] = ~s[4];
  73. s[5] = ~0;
  74. size = 12;
  75. } else {
  76. memcpy(&s[0], &ctx->from, 4);
  77. memcpy(&s[4], &ctx->to, 4);
  78. s[0] = ~s[0];
  79. s[1] = ~s[1];
  80. s[2] = ~s[2];
  81. s[3] = ~s[3];
  82. size = 8;
  83. }
  84. *ctx->check = csum_fold(csum_partial(s, size,
  85. ~csum_unfold(*ctx->check)));
  86. }
  87. int snmp_version(void *context, size_t hdrlen, unsigned char tag,
  88. const void *data, size_t datalen)
  89. {
  90. if (datalen != 1)
  91. return -EINVAL;
  92. if (*(unsigned char *)data > 1)
  93. return -ENOTSUPP;
  94. return 1;
  95. }
  96. int snmp_helper(void *context, size_t hdrlen, unsigned char tag,
  97. const void *data, size_t datalen)
  98. {
  99. struct snmp_ctx *ctx = (struct snmp_ctx *)context;
  100. __be32 *pdata;
  101. if (datalen != 4)
  102. return -EINVAL;
  103. pdata = (__be32 *)data;
  104. if (*pdata == ctx->from) {
  105. pr_debug("%s: %pI4 to %pI4\n", __func__,
  106. (void *)&ctx->from, (void *)&ctx->to);
  107. if (*ctx->check)
  108. fast_csum(ctx, (unsigned char *)data - ctx->begin);
  109. *pdata = ctx->to;
  110. }
  111. return 1;
  112. }
  113. static int snmp_translate(struct nf_conn *ct, int dir, struct sk_buff *skb)
  114. {
  115. struct iphdr *iph = ip_hdr(skb);
  116. struct udphdr *udph = (struct udphdr *)((__be32 *)iph + iph->ihl);
  117. u16 datalen = ntohs(udph->len) - sizeof(struct udphdr);
  118. char *data = (unsigned char *)udph + sizeof(struct udphdr);
  119. struct snmp_ctx ctx;
  120. int ret;
  121. if (dir == IP_CT_DIR_ORIGINAL) {
  122. ctx.from = ct->tuplehash[dir].tuple.src.u3.ip;
  123. ctx.to = ct->tuplehash[!dir].tuple.dst.u3.ip;
  124. } else {
  125. ctx.from = ct->tuplehash[!dir].tuple.src.u3.ip;
  126. ctx.to = ct->tuplehash[dir].tuple.dst.u3.ip;
  127. }
  128. if (ctx.from == ctx.to)
  129. return NF_ACCEPT;
  130. ctx.begin = (unsigned char *)udph + sizeof(struct udphdr);
  131. ctx.check = &udph->check;
  132. ret = asn1_ber_decoder(&nf_nat_snmp_basic_decoder, &ctx, data, datalen);
  133. if (ret < 0) {
  134. nf_ct_helper_log(skb, ct, "parser failed\n");
  135. return NF_DROP;
  136. }
  137. return NF_ACCEPT;
  138. }
  139. /* We don't actually set up expectations, just adjust internal IP
  140. * addresses if this is being NATted
  141. */
  142. static int help(struct sk_buff *skb, unsigned int protoff,
  143. struct nf_conn *ct,
  144. enum ip_conntrack_info ctinfo)
  145. {
  146. int dir = CTINFO2DIR(ctinfo);
  147. unsigned int ret;
  148. const struct iphdr *iph = ip_hdr(skb);
  149. const struct udphdr *udph = (struct udphdr *)((__be32 *)iph + iph->ihl);
  150. /* SNMP replies and originating SNMP traps get mangled */
  151. if (udph->source == htons(SNMP_PORT) && dir != IP_CT_DIR_REPLY)
  152. return NF_ACCEPT;
  153. if (udph->dest == htons(SNMP_TRAP_PORT) && dir != IP_CT_DIR_ORIGINAL)
  154. return NF_ACCEPT;
  155. /* No NAT? */
  156. if (!(ct->status & IPS_NAT_MASK))
  157. return NF_ACCEPT;
  158. /* Make sure the packet length is ok. So far, we were only guaranteed
  159. * to have a valid length IP header plus 8 bytes, which means we have
  160. * enough room for a UDP header. Just verify the UDP length field so we
  161. * can mess around with the payload.
  162. */
  163. if (ntohs(udph->len) != skb->len - (iph->ihl << 2)) {
  164. nf_ct_helper_log(skb, ct, "dropping malformed packet\n");
  165. return NF_DROP;
  166. }
  167. if (skb_ensure_writable(skb, skb->len)) {
  168. nf_ct_helper_log(skb, ct, "cannot mangle packet");
  169. return NF_DROP;
  170. }
  171. spin_lock_bh(&snmp_lock);
  172. ret = snmp_translate(ct, dir, skb);
  173. spin_unlock_bh(&snmp_lock);
  174. return ret;
  175. }
  176. static const struct nf_conntrack_expect_policy snmp_exp_policy = {
  177. .max_expected = 0,
  178. .timeout = 180,
  179. };
  180. static struct nf_conntrack_helper snmp_trap_helper __read_mostly = {
  181. .me = THIS_MODULE,
  182. .help = help,
  183. .expect_policy = &snmp_exp_policy,
  184. .name = "snmp_trap",
  185. .tuple.src.l3num = AF_INET,
  186. .tuple.src.u.udp.port = cpu_to_be16(SNMP_TRAP_PORT),
  187. .tuple.dst.protonum = IPPROTO_UDP,
  188. };
  189. static int __init nf_nat_snmp_basic_init(void)
  190. {
  191. BUG_ON(nf_nat_snmp_hook != NULL);
  192. RCU_INIT_POINTER(nf_nat_snmp_hook, help);
  193. return nf_conntrack_helper_register(&snmp_trap_helper);
  194. }
  195. static void __exit nf_nat_snmp_basic_fini(void)
  196. {
  197. RCU_INIT_POINTER(nf_nat_snmp_hook, NULL);
  198. synchronize_rcu();
  199. nf_conntrack_helper_unregister(&snmp_trap_helper);
  200. }
  201. module_init(nf_nat_snmp_basic_init);
  202. module_exit(nf_nat_snmp_basic_fini);