X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fnetfilter%2Fip_nat_snmp_basic.c;h=c33244263b9035a688c73816487a89c4a5381d62;hb=9464c7cf61b9433057924c36e6e02f303a00e768;hp=32d6e966aa13a0515dae4eae068a004311f3cc5f;hpb=ec9397bab20a628530ce3051167d3d0fcc2c1af7;p=linux-2.6.git diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c index 32d6e966a..c33244263 100644 --- a/net/ipv4/netfilter/ip_nat_snmp_basic.c +++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c @@ -44,14 +44,17 @@ * */ #include +#include #include #include #include #include #include #include +#include #include #include +#include #include #include #include @@ -65,7 +68,7 @@ MODULE_DESCRIPTION("Basic SNMP Application Layer Gateway"); #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 @@ -247,6 +250,7 @@ static unsigned char asn1_header_decode(struct asn1_ctx *ctx, if (!asn1_id_decode(ctx, cls, con, tag)) return 0; + def = len = 0; if (!asn1_length_decode(ctx, &def, &len)) return 0; @@ -666,7 +670,7 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx, unsigned char *eoc, *end, *p; unsigned long *lp, *id; unsigned long ul; - long l; + long l; *obj = NULL; id = NULL; @@ -696,11 +700,13 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx, 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); @@ -762,6 +768,7 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx, 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__); @@ -997,12 +1004,12 @@ static unsigned char snmp_trap_decode(struct asn1_ctx *ctx, 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; } @@ -1120,11 +1127,10 @@ static int snmp_parse_mangle(unsigned char *msg, 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 { @@ -1160,8 +1166,7 @@ static int snmp_parse_mangle(unsigned char *msg, if (!snmp_object_decode(&ctx, obj)) { if (*obj) { - if ((*obj)->id) - kfree((*obj)->id); + kfree((*obj)->id); kfree(*obj); } kfree(obj); @@ -1203,9 +1208,7 @@ static int snmp_parse_mangle(unsigned char *msg, * 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; @@ -1234,101 +1237,86 @@ static int snmp_translate(struct ip_conntrack *ct, 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 }, + }, +}; /***************************************************************************** * @@ -1336,29 +1324,28 @@ static struct ip_nat_helper snmp_trap = { * *****************************************************************************/ -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);