📄 ip_nat_snmp_basic.c
字号:
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)); }}static unsigned char snmp_trap_decode(struct asn1_ctx *ctx, struct snmp_v1_trap *trap, const struct oct1_map *map, u_int16_t *check){ unsigned int cls, con, tag, len; unsigned char *end; if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) return 0; if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OJI) return 0; if (!asn1_oid_decode(ctx, end, &trap->id, &trap->id_len)) return 0; if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) goto err_id_free; if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_IPA) || (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS))) goto err_id_free; if (!asn1_octets_decode(ctx, end, (unsigned char **)&trap->ip_address, &len)) goto err_id_free; /* IPv4 only */ if (len != 4) goto err_addr_free; mangle_address(ctx->begin, ctx->pointer - 4, map, check); if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) goto err_addr_free; if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) goto err_addr_free; if (!asn1_uint_decode(ctx, end, &trap->general)) goto err_addr_free; if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) goto err_addr_free; if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) goto err_addr_free; if (!asn1_uint_decode(ctx, end, &trap->specific)) goto err_addr_free; if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) goto err_addr_free; if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_TIT) || (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_INT))) goto err_addr_free; if (!asn1_ulong_decode(ctx, end, &trap->time)) goto err_addr_free; return 1;err_id_free: kfree(trap->id);err_addr_free: kfree((unsigned long *)trap->ip_address); return 0;}/***************************************************************************** * * Misc. routines * *****************************************************************************/static void hex_dump(unsigned char *buf, size_t len){ size_t i; for (i = 0; i < len; i++) { if (i && !(i % 16)) printk("\n"); printk("%02x ", *(buf + i)); } printk("\n");}/* * Parse and mangle SNMP message according to mapping. * (And this is the fucking 'basic' method). */static int snmp_parse_mangle(unsigned char *msg, u_int16_t len, const struct oct1_map *map, u_int16_t *check){ unsigned char *eoc, *end; unsigned int cls, con, tag, vers, pdutype; struct asn1_ctx ctx; struct asn1_octstr comm; struct snmp_object **obj; if (debug > 1) hex_dump(msg, len); asn1_open(&ctx, msg, len); /* * Start of SNMP message. */ if (!asn1_header_decode(&ctx, &eoc, &cls, &con, &tag)) return 0; if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ) return 0; /* * Version 1 or 2 handled. */ if (!asn1_header_decode(&ctx, &end, &cls, &con, &tag)) return 0; if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) return 0; if (!asn1_uint_decode (&ctx, end, &vers)) return 0; if (debug > 1) printk(KERN_DEBUG "bsalg: snmp version: %u\n", vers + 1); if (vers > 1) return 1; /* * Community. */ if (!asn1_header_decode (&ctx, &end, &cls, &con, &tag)) return 0; if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OTS) return 0; if (!asn1_octets_decode(&ctx, end, &comm.data, &comm.len)) return 0; if (debug > 1) { unsigned int i; printk(KERN_DEBUG "bsalg: community: "); for (i = 0; i < comm.len; i++) printk("%c", comm.data[i]); printk("\n"); } kfree(comm.data); /* * PDU type */ if (!asn1_header_decode(&ctx, &eoc, &cls, &con, &pdutype)) return 0; if (cls != ASN1_CTX || con != ASN1_CON) return 0; if (debug > 1) { unsigned char *pdus[] = { [SNMP_PDU_GET] = "get", [SNMP_PDU_NEXT] = "get-next", [SNMP_PDU_RESPONSE] = "response", [SNMP_PDU_SET] = "set", [SNMP_PDU_TRAP1] = "trapv1", [SNMP_PDU_BULK] = "bulk", [SNMP_PDU_INFORM] = "inform", [SNMP_PDU_TRAP2] = "trapv2" }; if (pdutype > SNMP_PDU_TRAP2) printk(KERN_DEBUG "bsalg: bad pdu type %u\n", pdutype); else printk(KERN_DEBUG "bsalg: pdu: %s\n", pdus[pdutype]); } if (pdutype != SNMP_PDU_RESPONSE && pdutype != SNMP_PDU_TRAP1 && pdutype != SNMP_PDU_TRAP2) return 1; /* * Request header or v1 trap */ if (pdutype == SNMP_PDU_TRAP1) { 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) return ret; } else { struct snmp_request req; if (!snmp_request_decode(&ctx, &req)) return 0; if (debug > 1) printk(KERN_DEBUG "bsalg: request: id=0x%lx error_status=%u " "error_index=%u\n", req.id, req.error_status, req.error_index); } /* * Loop through objects, look for IP addresses to mangle. */ if (!asn1_header_decode(&ctx, &eoc, &cls, &con, &tag)) return 0; if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ) return 0; obj = kmalloc(sizeof(struct snmp_object), GFP_ATOMIC); if (obj == NULL) { if (net_ratelimit()) printk(KERN_WARNING "OOM in bsalg(%d)\n", __LINE__); return 0; } while (!asn1_eoc_decode(&ctx, eoc)) { unsigned int i; if (!snmp_object_decode(&ctx, obj)) { if (*obj) { kfree((*obj)->id); kfree(*obj); } kfree(obj); return 0; } if (debug > 1) { printk(KERN_DEBUG "bsalg: object: "); for (i = 0; i < (*obj)->id_len; i++) { if (i > 0) printk("."); printk("%lu", (*obj)->id[i]); } printk(": type=%u\n", (*obj)->type); } if ((*obj)->type == SNMP_IPADDR) mangle_address(ctx.begin, ctx.pointer - 4 , map, check); kfree((*obj)->id); kfree(*obj); } kfree(obj); if (!asn1_eoc_decode(&ctx, eoc)) return 0; return 1;}/***************************************************************************** * * NAT routines. * *****************************************************************************//* * SNMP translation routine. */static int snmp_translate(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, struct sk_buff **pskb){ struct iphdr *iph = (*pskb)->nh.iph; struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl); u_int16_t udplen = ntohs(udph->len); u_int16_t paylen = udplen - sizeof(struct udphdr); int dir = CTINFO2DIR(ctinfo); struct oct1_map map; /* * Determine mappping for application layer addresses based * on NAT manipulations for the packet. */ 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); } 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); } if (map.from == map.to) return NF_ACCEPT; if (!snmp_parse_mangle((unsigned char *)udph + sizeof(struct udphdr), paylen, &map, &udph->check)) { if (net_ratelimit()) printk(KERN_WARNING "bsalg: parser failed\n"); return NF_DROP; } return NF_ACCEPT;}/* 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); /* 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; /* * 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)) { 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 (!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 ret;}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 }, },};/***************************************************************************** * * Module stuff. * *****************************************************************************/ static int __init init(void){ int ret = 0; ret = ip_conntrack_helper_register(&snmp_helper); if (ret < 0) return ret; ret = ip_conntrack_helper_register(&snmp_trap_helper); if (ret < 0) { ip_conntrack_helper_unregister(&snmp_helper); return ret; } return ret;}static void __exit fini(void){ ip_conntrack_helper_unregister(&snmp_helper); ip_conntrack_helper_unregister(&snmp_trap_helper);}module_init(init);module_exit(fini);module_param(debug, bool, 0600);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -