#include <linux/moduleparam.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
#include <linux/netfilter_ipv4/ip_nat_helper.h>
#include <linux/ip.h>
#include <net/checksum.h>
#define NOCT1(n) (u_int8_t )((n) & 0xff)
static int debug;
-static spinlock_t snmp_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(snmp_lock);
/*
* Application layer address mapping mimics the NAT mapping, but
* SNMP translation routine.
*/
static int snmp_translate(struct ip_conntrack *ct,
- struct ip_nat_info *info,
enum ip_conntrack_info ctinfo,
- unsigned int hooknum,
struct sk_buff **pskb)
{
struct iphdr *iph = (*pskb)->nh.iph;
if (!snmp_parse_mangle((unsigned char *)udph + sizeof(struct udphdr),
paylen, &map, &udph->check)) {
- printk(KERN_WARNING "bsalg: parser failed\n");
+ if (net_ratelimit())
+ printk(KERN_WARNING "bsalg: parser failed\n");
return NF_DROP;
}
return NF_ACCEPT;
}
-/*
- * NAT helper function, packets arrive here from NAT code.
- */
-static unsigned int nat_help(struct ip_conntrack *ct,
- struct ip_conntrack_expect *exp,
- struct ip_nat_info *info,
- enum ip_conntrack_info ctinfo,
- unsigned int hooknum,
- struct sk_buff **pskb)
+/* We don't actually set up expectations, just adjust internal IP
+ * addresses if this is being NATted */
+static int help(struct sk_buff **pskb,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo)
{
int dir = CTINFO2DIR(ctinfo);
+ unsigned int ret;
struct iphdr *iph = (*pskb)->nh.iph;
struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl);
-
- if (!skb_ip_make_writable(pskb, (*pskb)->len))
- return NF_DROP;
- spin_lock_bh(&snmp_lock);
-
- /*
- * Translate snmp replies on pre-routing (DNAT) and snmp traps
- * on post routing (SNAT).
- */
- if (!((dir == IP_CT_DIR_REPLY && hooknum == NF_IP_PRE_ROUTING &&
- udph->source == ntohs(SNMP_PORT)) ||
- (dir == IP_CT_DIR_ORIGINAL && hooknum == NF_IP_POST_ROUTING &&
- udph->dest == ntohs(SNMP_TRAP_PORT)))) {
- spin_unlock_bh(&snmp_lock);
+ /* SNMP replies and originating SNMP traps get mangled */
+ if (udph->source == ntohs(SNMP_PORT) && dir != IP_CT_DIR_REPLY)
+ return NF_ACCEPT;
+ if (udph->dest == ntohs(SNMP_TRAP_PORT) && dir != IP_CT_DIR_ORIGINAL)
+ return NF_ACCEPT;
+
+ /* No NAT? */
+ if (!(ct->status & IPS_NAT_MASK))
return NF_ACCEPT;
- }
- if (debug > 1) {
- printk(KERN_DEBUG "bsalg: dir=%s hook=%d manip=%s len=%d "
- "src=%u.%u.%u.%u:%u dst=%u.%u.%u.%u:%u "
- "osrc=%u.%u.%u.%u odst=%u.%u.%u.%u "
- "rsrc=%u.%u.%u.%u rdst=%u.%u.%u.%u "
- "\n",
- dir == IP_CT_DIR_REPLY ? "reply" : "orig", hooknum,
- HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC ? "snat" :
- "dnat", (*pskb)->len,
- NIPQUAD(iph->saddr), ntohs(udph->source),
- NIPQUAD(iph->daddr), ntohs(udph->dest),
- NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
- NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip),
- NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip),
- NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip));
- }
-
/*
* Make sure the packet length is ok. So far, we were only guaranteed
* to have a valid length IP header plus 8 bytes, which means we have
* enough room for a UDP header. Just verify the UDP length field so we
* can mess around with the payload.
*/
- if (ntohs(udph->len) == (*pskb)->len - (iph->ihl << 2)) {
- int ret = snmp_translate(ct, info, ctinfo, hooknum, pskb);
- spin_unlock_bh(&snmp_lock);
- return ret;
+ if (ntohs(udph->len) != (*pskb)->len - (iph->ihl << 2)) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "SNMP: dropping malformed packet "
+ "src=%u.%u.%u.%u dst=%u.%u.%u.%u\n",
+ NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
+ return NF_DROP;
}
-
- if (net_ratelimit())
- printk(KERN_WARNING "bsalg: dropping malformed packet "
- "src=%u.%u.%u.%u dst=%u.%u.%u.%u\n",
- NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
+
+ if (!skb_ip_make_writable(pskb, (*pskb)->len))
+ return NF_DROP;
+
+ spin_lock_bh(&snmp_lock);
+ ret = snmp_translate(ct, ctinfo, pskb);
spin_unlock_bh(&snmp_lock);
- return NF_DROP;
+ return ret;
}
-static struct ip_nat_helper snmp = {
- { NULL, NULL },
- "snmp",
- 0,
- THIS_MODULE,
- { { 0, { .udp = { __constant_htons(SNMP_PORT) } } },
- { 0, { 0 }, IPPROTO_UDP } },
- { { 0, { .udp = { 0xFFFF } } },
- { 0, { 0 }, 0xFFFF } },
- nat_help, NULL };
-
-static struct ip_nat_helper snmp_trap = {
- { NULL, NULL },
- "snmp_trap",
- 0,
- THIS_MODULE,
- { { 0, { .udp = { __constant_htons(SNMP_TRAP_PORT) } } },
- { 0, { 0 }, IPPROTO_UDP } },
- { { 0, { .udp = { 0xFFFF } } },
- { 0, { 0 }, 0xFFFF } },
- nat_help, NULL };
+static struct ip_conntrack_helper snmp_helper = {
+ .max_expected = 0,
+ .timeout = 180,
+ .me = THIS_MODULE,
+ .help = help,
+ .name = "snmp",
+
+ .tuple = { .src = { .u = { __constant_htons(SNMP_PORT) } },
+ .dst = { .protonum = IPPROTO_UDP },
+ },
+ .mask = { .src = { .u = { 0xFFFF } },
+ .dst = { .protonum = 0xFF },
+ },
+};
+
+static struct ip_conntrack_helper snmp_trap_helper = {
+ .max_expected = 0,
+ .timeout = 180,
+ .me = THIS_MODULE,
+ .help = help,
+ .name = "snmp_trap",
+
+ .tuple = { .src = { .u = { __constant_htons(SNMP_TRAP_PORT) } },
+ .dst = { .protonum = IPPROTO_UDP },
+ },
+ .mask = { .src = { .u = { 0xFFFF } },
+ .dst = { .protonum = 0xFF },
+ },
+};
/*****************************************************************************
*
{
int ret = 0;
- ret = ip_nat_helper_register(&snmp);
+ ret = ip_conntrack_helper_register(&snmp_helper);
if (ret < 0)
return ret;
- ret = ip_nat_helper_register(&snmp_trap);
+ ret = ip_conntrack_helper_register(&snmp_trap_helper);
if (ret < 0) {
- ip_nat_helper_unregister(&snmp);
+ ip_conntrack_helper_unregister(&snmp_helper);
return ret;
}
return ret;
static void __exit fini(void)
{
- ip_nat_helper_unregister(&snmp);
- ip_nat_helper_unregister(&snmp_trap);
- synchronize_net();
+ ip_conntrack_helper_unregister(&snmp_helper);
+ ip_conntrack_helper_unregister(&snmp_trap_helper);
}
module_init(init);