X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fnetfilter%2Fip_nat_snmp_basic.c;h=c3d9f3b090c44851a279eb8ee7aa5a5c9b22464a;hb=refs%2Fheads%2Fvserver;hp=00b4effb65f68fbb14855db306b51f970aa9dcc3;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;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 00b4effb6..c3d9f3b09 100644 --- a/net/ipv4/netfilter/ip_nat_snmp_basic.c +++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c @@ -43,14 +43,17 @@ * 2000-08-06: Convert to new helper API (Harald Welte). * */ -#include +#include #include #include #include +#include #include #include +#include #include #include +#include #include #include #include @@ -61,10 +64,10 @@ MODULE_DESCRIPTION("Basic SNMP Application Layer Gateway"); #define SNMP_PORT 161 #define SNMP_TRAP_PORT 162 -#define NOCT1(n) (u_int8_t )((n) & 0xff) +#define NOCT1(n) (*(u8 *)n) 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 @@ -246,13 +249,14 @@ 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; if (def) *eoc = ctx->pointer + len; else - *eoc = 0; + *eoc = NULL; return 1; } @@ -609,7 +613,7 @@ struct snmp_v1_trap static inline void mangle_address(unsigned char *begin, unsigned char *addr, const struct oct1_map *map, - u_int16_t *check); + __sum16 *check); struct snmp_cnv { unsigned int class; @@ -665,7 +669,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; @@ -695,11 +699,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); @@ -761,6 +767,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__); @@ -862,10 +869,64 @@ static unsigned char snmp_request_decode(struct asn1_ctx *ctx, return 1; } +/* + * Fast checksum update for possibly oddly-aligned UDP byte, from the + * code example in the draft. + */ +static void fast_csum(__sum16 *csum, + const unsigned char *optr, + const unsigned char *nptr, + int offset) +{ + unsigned char s[4]; + + if (offset & 1) { + s[0] = s[2] = 0; + s[1] = ~*optr; + s[3] = *nptr; + } else { + s[1] = s[3] = 0; + s[0] = ~*optr; + s[2] = *nptr; + } + + *csum = csum_fold(csum_partial(s, 4, ~csum_unfold(*csum))); +} + +/* + * Mangle IP address. + * - begin points to the start of the snmp messgae + * - addr points to the start of the address + */ +static inline void mangle_address(unsigned char *begin, + unsigned char *addr, + const struct oct1_map *map, + __sum16 *check) +{ + if (map->from == NOCT1(addr)) { + u_int32_t old; + + if (debug) + memcpy(&old, (unsigned char *)addr, sizeof(old)); + + *addr = map->to; + + /* Update UDP checksum if being used */ + if (*check) { + fast_csum(check, + &map->from, &map->to, addr - begin); + } + + if (debug) + printk(KERN_DEBUG "bsalg: mapped %u.%u.%u.%u to " + "%u.%u.%u.%u\n", NIPQUAD(old), NIPQUAD(*addr)); + } +} + static unsigned char snmp_trap_decode(struct asn1_ctx *ctx, struct snmp_v1_trap *trap, const struct oct1_map *map, - u_int16_t *check) + __sum16 *check) { unsigned int cls, con, tag, len; unsigned char *end; @@ -925,12 +986,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; } @@ -952,77 +1013,6 @@ static void hex_dump(unsigned char *buf, size_t len) printk("\n"); } -/* - * Fast checksum update for possibly oddly-aligned UDP byte, from the - * code example in the draft. - */ -static void fast_csum(unsigned char *csum, - const unsigned char *optr, - const unsigned char *nptr, - int odd) -{ - long x, old, new; - - x = csum[0] * 256 + csum[1]; - - x =~ x & 0xFFFF; - - if (odd) old = optr[0] * 256; - else old = optr[0]; - - x -= old & 0xFFFF; - if (x <= 0) { - x--; - x &= 0xFFFF; - } - - if (odd) new = nptr[0] * 256; - else new = nptr[0]; - - x += new & 0xFFFF; - if (x & 0x10000) { - x++; - x &= 0xFFFF; - } - - x =~ x & 0xFFFF; - csum[0] = x / 256; - csum[1] = x & 0xFF; -} - -/* - * Mangle IP address. - * - begin points to the start of the snmp messgae - * - addr points to the start of the address - */ -static inline void mangle_address(unsigned char *begin, - unsigned char *addr, - const struct oct1_map *map, - u_int16_t *check) -{ - if (map->from == NOCT1(*addr)) { - u_int32_t old; - - if (debug) - memcpy(&old, (unsigned char *)addr, sizeof(old)); - - *addr = map->to; - - /* Update UDP checksum if being used */ - if (*check) { - unsigned char odd = !((addr - begin) % 2); - - fast_csum((unsigned char *)check, - &map->from, &map->to, odd); - - } - - if (debug) - printk(KERN_DEBUG "bsalg: mapped %u.%u.%u.%u to " - "%u.%u.%u.%u\n", NIPQUAD(old), NIPQUAD(*addr)); - } -} - /* * Parse and mangle SNMP message according to mapping. * (And this is the fucking 'basic' method). @@ -1030,7 +1020,7 @@ static inline void mangle_address(unsigned char *begin, static int snmp_parse_mangle(unsigned char *msg, u_int16_t len, const struct oct1_map *map, - u_int16_t *check) + __sum16 *check) { unsigned char *eoc, *end; unsigned int cls, con, tag, vers, pdutype; @@ -1119,11 +1109,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 { @@ -1159,8 +1148,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); @@ -1202,13 +1190,11 @@ 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; - struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl); + struct udphdr *udph = (struct udphdr *)((__be32 *)iph + iph->ihl); u_int16_t udplen = ntohs(udph->len); u_int16_t paylen = udplen - sizeof(struct udphdr); int dir = CTINFO2DIR(ctinfo); @@ -1220,12 +1206,12 @@ static int snmp_translate(struct ip_conntrack *ct, */ if (dir == IP_CT_DIR_ORIGINAL) { /* SNAT traps */ - map.from = NOCT1(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip); - map.to = NOCT1(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip); + map.from = NOCT1(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip); + map.to = NOCT1(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip); } else { /* DNAT replies */ - map.from = NOCT1(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip); - map.to = NOCT1(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip); + map.from = NOCT1(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip); + map.to = NOCT1(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip); } if (map.from == map.to) @@ -1233,98 +1219,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); - 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 == htons(SNMP_PORT) && dir != IP_CT_DIR_REPLY) + return NF_ACCEPT; + if (udph->dest == htons(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 = {.udp = {.port = __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 = {.udp = {.port = __constant_htons(SNMP_TRAP_PORT)}}}, + .dst = {.protonum = IPPROTO_UDP}, + }, + .mask = {.src = {.u = {0xFFFF}}, + .dst = {.protonum = 0xFF}, + }, +}; /***************************************************************************** * @@ -1332,29 +1306,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_PARM(debug, "i"); +module_param(debug, int, 0600);