📄 ip_nat_snmp_basic.c
字号:
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) { if ((*obj)->id) 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, 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); 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)) { 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){ int dir = CTINFO2DIR(ctinfo); 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); 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 (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)); spin_unlock_bh(&snmp_lock); return NF_DROP;}static struct ip_nat_helper snmp = { { NULL, NULL }, "snmp", IP_NAT_HELPER_F_STANDALONE, 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", IP_NAT_HELPER_F_STANDALONE, THIS_MODULE, { { 0, { .udp = { __constant_htons(SNMP_TRAP_PORT) } } }, { 0, { 0 }, IPPROTO_UDP } }, { { 0, { .udp = { 0xFFFF } } }, { 0, { 0 }, 0xFFFF } }, nat_help, NULL };/***************************************************************************** * * Module stuff. * *****************************************************************************/ static int __init init(void){ int ret = 0; ret = ip_nat_helper_register(&snmp); if (ret < 0) return ret; ret = ip_nat_helper_register(&snmp_trap); if (ret < 0) { ip_nat_helper_unregister(&snmp); return ret; } return ret;}static void __exit fini(void){ ip_nat_helper_unregister(&snmp); ip_nat_helper_unregister(&snmp_trap); br_write_lock_bh(BR_NETPROTO_LOCK); br_write_unlock_bh(BR_NETPROTO_LOCK);}module_init(init);module_exit(fini);MODULE_PARM(debug, "i");MODULE_DESCRIPTION("Basic SNMP Application Layer Gateway");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -