*
*/
#include <linux/config.h>
+#include <linux/in.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#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 <linux/udp.h>
#include <net/checksum.h>
#include <net/udp.h>
#include <asm/uaccess.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
if (!asn1_id_decode(ctx, cls, con, tag))
return 0;
+ def = len = 0;
if (!asn1_length_decode(ctx, &def, &len))
return 0;
unsigned char *eoc, *end, *p;
unsigned long *lp, *id;
unsigned long ul;
- long l;
+ long l;
*obj = NULL;
id = NULL;
return 0;
}
+ type = 0;
if (!snmp_tag_cls2syntax(tag, cls, &type)) {
kfree(id);
return 0;
}
+ l = 0;
switch (type) {
case SNMP_INTEGER:
len = sizeof(long);
len *= sizeof(unsigned long);
*obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC);
if (*obj == NULL) {
+ kfree(lp);
kfree(id);
if (net_ratelimit())
printk("OOM in bsalg (%d)\n", __LINE__);
return 1;
+err_addr_free:
+ kfree((unsigned long *)trap->ip_address);
+
err_id_free:
kfree(trap->id);
-err_addr_free:
- kfree((unsigned long *)trap->ip_address);
-
return 0;
}
struct snmp_v1_trap trap;
unsigned char ret = snmp_trap_decode(&ctx, &trap, map, check);
- /* Discard trap allocations regardless */
- kfree(trap.id);
- kfree((unsigned long *)trap.ip_address);
-
- if (!ret)
+ if (ret) {
+ kfree(trap.id);
+ kfree((unsigned long *)trap.ip_address);
+ } else
return ret;
} else {
if (!snmp_object_decode(&ctx, obj)) {
if (*obj) {
- if ((*obj)->id)
- kfree((*obj)->id);
+ kfree((*obj)->id);
kfree(*obj);
}
kfree(obj);
* 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_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 },
+ },
+};
/*****************************************************************************
*
*
*****************************************************************************/
-static int __init init(void)
+static int __init ip_nat_snmp_basic_init(void)
{
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)
+static void __exit ip_nat_snmp_basic_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);
-module_exit(fini);
+module_init(ip_nat_snmp_basic_init);
+module_exit(ip_nat_snmp_basic_fini);
module_param(debug, bool, 0600);