📄 nf_nat_snmp_basic.c
字号:
/* * nf_nat_snmp_basic.c * * Basic SNMP Application Layer Gateway * * This IP NAT module is intended for use with SNMP network * discovery and monitoring applications where target networks use * conflicting private address realms. * * Static NAT is used to remap the networks from the view of the network * management system at the IP layer, and this module remaps some application * layer addresses to match. * * The simplest form of ALG is performed, where only tagged IP addresses * are modified. The module does not need to be MIB aware and only scans * messages at the ASN.1/BER level. * * Currently, only SNMPv1 and SNMPv2 are supported. * * More information on ALG and associated issues can be found in * RFC 2962 * * The ASB.1/BER parsing code is derived from the gxsnmp package by Gregory * McLean & Jochen Friedrich, stripped down for use in the kernel. * * Copyright (c) 2000 RP Internet (www.rpi.net.au). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: James Morris <jmorris@intercode.com.au> */#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/in.h>#include <linux/ip.h>#include <linux/udp.h>#include <net/checksum.h>#include <net/udp.h>#include <net/netfilter/nf_nat.h>#include <net/netfilter/nf_conntrack_helper.h>#include <net/netfilter/nf_nat_helper.h>MODULE_LICENSE("GPL");MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");MODULE_DESCRIPTION("Basic SNMP Application Layer Gateway");MODULE_ALIAS("ip_nat_snmp_basic");#define SNMP_PORT 161#define SNMP_TRAP_PORT 162#define NOCT1(n) (*(u8 *)n)static int debug;static DEFINE_SPINLOCK(snmp_lock);/* * Application layer address mapping mimics the NAT mapping, but * only for the first octet in this case (a more flexible system * can be implemented if needed). */struct oct1_map{ u_int8_t from; u_int8_t to;};/***************************************************************************** * * Basic ASN.1 decoding routines (gxsnmp author Dirk Wisse) * *****************************************************************************//* Class */#define ASN1_UNI 0 /* Universal */#define ASN1_APL 1 /* Application */#define ASN1_CTX 2 /* Context */#define ASN1_PRV 3 /* Private *//* Tag */#define ASN1_EOC 0 /* End Of Contents */#define ASN1_BOL 1 /* Boolean */#define ASN1_INT 2 /* Integer */#define ASN1_BTS 3 /* Bit String */#define ASN1_OTS 4 /* Octet String */#define ASN1_NUL 5 /* Null */#define ASN1_OJI 6 /* Object Identifier */#define ASN1_OJD 7 /* Object Description */#define ASN1_EXT 8 /* External */#define ASN1_SEQ 16 /* Sequence */#define ASN1_SET 17 /* Set */#define ASN1_NUMSTR 18 /* Numerical String */#define ASN1_PRNSTR 19 /* Printable String */#define ASN1_TEXSTR 20 /* Teletext String */#define ASN1_VIDSTR 21 /* Video String */#define ASN1_IA5STR 22 /* IA5 String */#define ASN1_UNITIM 23 /* Universal Time */#define ASN1_GENTIM 24 /* General Time */#define ASN1_GRASTR 25 /* Graphical String */#define ASN1_VISSTR 26 /* Visible String */#define ASN1_GENSTR 27 /* General String *//* Primitive / Constructed methods*/#define ASN1_PRI 0 /* Primitive */#define ASN1_CON 1 /* Constructed *//* * Error codes. */#define ASN1_ERR_NOERROR 0#define ASN1_ERR_DEC_EMPTY 2#define ASN1_ERR_DEC_EOC_MISMATCH 3#define ASN1_ERR_DEC_LENGTH_MISMATCH 4#define ASN1_ERR_DEC_BADVALUE 5/* * ASN.1 context. */struct asn1_ctx{ int error; /* Error condition */ unsigned char *pointer; /* Octet just to be decoded */ unsigned char *begin; /* First octet */ unsigned char *end; /* Octet after last octet */};/* * Octet string (not null terminated) */struct asn1_octstr{ unsigned char *data; unsigned int len;};static void asn1_open(struct asn1_ctx *ctx, unsigned char *buf, unsigned int len){ ctx->begin = buf; ctx->end = buf + len; ctx->pointer = buf; ctx->error = ASN1_ERR_NOERROR;}static unsigned char asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch){ if (ctx->pointer >= ctx->end) { ctx->error = ASN1_ERR_DEC_EMPTY; return 0; } *ch = *(ctx->pointer)++; return 1;}static unsigned char asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag){ unsigned char ch; *tag = 0; do { if (!asn1_octet_decode(ctx, &ch)) return 0; *tag <<= 7; *tag |= ch & 0x7F; } while ((ch & 0x80) == 0x80); return 1;}static unsigned char asn1_id_decode(struct asn1_ctx *ctx, unsigned int *cls, unsigned int *con, unsigned int *tag){ unsigned char ch; if (!asn1_octet_decode(ctx, &ch)) return 0; *cls = (ch & 0xC0) >> 6; *con = (ch & 0x20) >> 5; *tag = (ch & 0x1F); if (*tag == 0x1F) { if (!asn1_tag_decode(ctx, tag)) return 0; } return 1;}static unsigned char asn1_length_decode(struct asn1_ctx *ctx, unsigned int *def, unsigned int *len){ unsigned char ch, cnt; if (!asn1_octet_decode(ctx, &ch)) return 0; if (ch == 0x80) *def = 0; else { *def = 1; if (ch < 0x80) *len = ch; else { cnt = (unsigned char) (ch & 0x7F); *len = 0; while (cnt > 0) { if (!asn1_octet_decode(ctx, &ch)) return 0; *len <<= 8; *len |= ch; cnt--; } } } return 1;}static unsigned char asn1_header_decode(struct asn1_ctx *ctx, unsigned char **eoc, unsigned int *cls, unsigned int *con, unsigned int *tag){ unsigned int def, len; 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 = NULL; return 1;}static unsigned char asn1_eoc_decode(struct asn1_ctx *ctx, unsigned char *eoc){ unsigned char ch; if (eoc == 0) { if (!asn1_octet_decode(ctx, &ch)) return 0; if (ch != 0x00) { ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; return 0; } if (!asn1_octet_decode(ctx, &ch)) return 0; if (ch != 0x00) { ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; return 0; } return 1; } else { if (ctx->pointer != eoc) { ctx->error = ASN1_ERR_DEC_LENGTH_MISMATCH; return 0; } return 1; }}static unsigned char asn1_null_decode(struct asn1_ctx *ctx, unsigned char *eoc){ ctx->pointer = eoc; return 1;}static unsigned char asn1_long_decode(struct asn1_ctx *ctx, unsigned char *eoc, long *integer){ unsigned char ch; unsigned int len; if (!asn1_octet_decode(ctx, &ch)) return 0; *integer = (signed char) ch; len = 1; while (ctx->pointer < eoc) { if (++len > sizeof (long)) { ctx->error = ASN1_ERR_DEC_BADVALUE; return 0; } if (!asn1_octet_decode(ctx, &ch)) return 0; *integer <<= 8; *integer |= ch; } return 1;}static unsigned char asn1_uint_decode(struct asn1_ctx *ctx, unsigned char *eoc, unsigned int *integer){ unsigned char ch; unsigned int len; if (!asn1_octet_decode(ctx, &ch)) return 0; *integer = ch; if (ch == 0) len = 0; else len = 1; while (ctx->pointer < eoc) { if (++len > sizeof (unsigned int)) { ctx->error = ASN1_ERR_DEC_BADVALUE; return 0; } if (!asn1_octet_decode(ctx, &ch)) return 0; *integer <<= 8; *integer |= ch; } return 1;}static unsigned char asn1_ulong_decode(struct asn1_ctx *ctx, unsigned char *eoc, unsigned long *integer){ unsigned char ch; unsigned int len; if (!asn1_octet_decode(ctx, &ch)) return 0; *integer = ch; if (ch == 0) len = 0; else len = 1; while (ctx->pointer < eoc) { if (++len > sizeof (unsigned long)) { ctx->error = ASN1_ERR_DEC_BADVALUE; return 0; } if (!asn1_octet_decode(ctx, &ch)) return 0; *integer <<= 8; *integer |= ch; } return 1;}static unsigned char asn1_octets_decode(struct asn1_ctx *ctx, unsigned char *eoc, unsigned char **octets, unsigned int *len){ unsigned char *ptr; *len = 0; *octets = kmalloc(eoc - ctx->pointer, GFP_ATOMIC); if (*octets == NULL) { if (net_ratelimit()) printk("OOM in bsalg (%d)\n", __LINE__); return 0; } ptr = *octets; while (ctx->pointer < eoc) { if (!asn1_octet_decode(ctx, (unsigned char *)ptr++)) { kfree(*octets); *octets = NULL; return 0; } (*len)++; } return 1;}static unsigned char asn1_subid_decode(struct asn1_ctx *ctx, unsigned long *subid){ unsigned char ch; *subid = 0; do { if (!asn1_octet_decode(ctx, &ch)) return 0; *subid <<= 7; *subid |= ch & 0x7F; } while ((ch & 0x80) == 0x80); return 1;}static unsigned char asn1_oid_decode(struct asn1_ctx *ctx, unsigned char *eoc, unsigned long **oid, unsigned int *len){ unsigned long subid; unsigned int size; unsigned long *optr; size = eoc - ctx->pointer + 1; *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC); if (*oid == NULL) { if (net_ratelimit()) printk("OOM in bsalg (%d)\n", __LINE__); return 0; } optr = *oid; if (!asn1_subid_decode(ctx, &subid)) { kfree(*oid); *oid = NULL; return 0; } if (subid < 40) { optr [0] = 0; optr [1] = subid; } else if (subid < 80) { optr [0] = 1; optr [1] = subid - 40; } else { optr [0] = 2; optr [1] = subid - 80; } *len = 2; optr += 2; while (ctx->pointer < eoc) { if (++(*len) > size) { ctx->error = ASN1_ERR_DEC_BADVALUE; kfree(*oid); *oid = NULL; return 0; } if (!asn1_subid_decode(ctx, optr++)) { kfree(*oid); *oid = NULL; return 0; } } return 1;}/***************************************************************************** * * SNMP decoding routines (gxsnmp author Dirk Wisse) * *****************************************************************************//* SNMP Versions */#define SNMP_V1 0#define SNMP_V2C 1#define SNMP_V2 2#define SNMP_V3 3/* Default Sizes */#define SNMP_SIZE_COMM 256#define SNMP_SIZE_OBJECTID 128#define SNMP_SIZE_BUFCHR 256#define SNMP_SIZE_BUFINT 128#define SNMP_SIZE_SMALLOBJECTID 16/* Requests */#define SNMP_PDU_GET 0#define SNMP_PDU_NEXT 1#define SNMP_PDU_RESPONSE 2#define SNMP_PDU_SET 3#define SNMP_PDU_TRAP1 4#define SNMP_PDU_BULK 5#define SNMP_PDU_INFORM 6#define SNMP_PDU_TRAP2 7/* Errors */#define SNMP_NOERROR 0#define SNMP_TOOBIG 1#define SNMP_NOSUCHNAME 2#define SNMP_BADVALUE 3#define SNMP_READONLY 4#define SNMP_GENERROR 5#define SNMP_NOACCESS 6#define SNMP_WRONGTYPE 7#define SNMP_WRONGLENGTH 8#define SNMP_WRONGENCODING 9#define SNMP_WRONGVALUE 10#define SNMP_NOCREATION 11#define SNMP_INCONSISTENTVALUE 12#define SNMP_RESOURCEUNAVAILABLE 13#define SNMP_COMMITFAILED 14#define SNMP_UNDOFAILED 15#define SNMP_AUTHORIZATIONERROR 16#define SNMP_NOTWRITABLE 17#define SNMP_INCONSISTENTNAME 18/* General SNMP V1 Traps */#define SNMP_TRAP_COLDSTART 0#define SNMP_TRAP_WARMSTART 1#define SNMP_TRAP_LINKDOWN 2#define SNMP_TRAP_LINKUP 3#define SNMP_TRAP_AUTFAILURE 4#define SNMP_TRAP_EQPNEIGHBORLOSS 5#define SNMP_TRAP_ENTSPECIFIC 6/* SNMPv1 Types */#define SNMP_NULL 0#define SNMP_INTEGER 1 /* l */#define SNMP_OCTETSTR 2 /* c */#define SNMP_DISPLAYSTR 2 /* c */#define SNMP_OBJECTID 3 /* ul */#define SNMP_IPADDR 4 /* uc */#define SNMP_COUNTER 5 /* ul */#define SNMP_GAUGE 6 /* ul */#define SNMP_TIMETICKS 7 /* ul */#define SNMP_OPAQUE 8 /* c *//* Additional SNMPv2 Types */#define SNMP_UINTEGER 5 /* ul */#define SNMP_BITSTR 9 /* uc */#define SNMP_NSAP 10 /* uc */#define SNMP_COUNTER64 11 /* ul */#define SNMP_NOSUCHOBJECT 12#define SNMP_NOSUCHINSTANCE 13#define SNMP_ENDOFMIBVIEW 14union snmp_syntax{ unsigned char uc[0]; /* 8 bit unsigned */ char c[0]; /* 8 bit signed */ unsigned long ul[0]; /* 32 bit unsigned */ long l[0]; /* 32 bit signed */};struct snmp_object{ unsigned long *id; unsigned int id_len; unsigned short type; unsigned int syntax_len; union snmp_syntax syntax;};struct snmp_request{ unsigned long id; unsigned int error_status; unsigned int error_index;};struct snmp_v1_trap{ unsigned long *id; unsigned int id_len; unsigned long ip_address; /* pointer */ unsigned int general; unsigned int specific; unsigned long time;};/* SNMP types */#define SNMP_IPA 0#define SNMP_CNT 1#define SNMP_GGE 2#define SNMP_TIT 3#define SNMP_OPQ 4#define SNMP_C64 6/* SNMP errors */#define SERR_NSO 0#define SERR_NSI 1#define SERR_EOM 2static inline void mangle_address(unsigned char *begin, unsigned char *addr, const struct oct1_map *map, __sum16 *check);struct snmp_cnv{ unsigned int class; unsigned int tag; int syntax;};static struct snmp_cnv snmp_conv [] ={ {ASN1_UNI, ASN1_NUL, SNMP_NULL}, {ASN1_UNI, ASN1_INT, SNMP_INTEGER}, {ASN1_UNI, ASN1_OTS, SNMP_OCTETSTR}, {ASN1_UNI, ASN1_OTS, SNMP_DISPLAYSTR}, {ASN1_UNI, ASN1_OJI, SNMP_OBJECTID}, {ASN1_APL, SNMP_IPA, SNMP_IPADDR}, {ASN1_APL, SNMP_CNT, SNMP_COUNTER}, /* Counter32 */ {ASN1_APL, SNMP_GGE, SNMP_GAUGE}, /* Gauge32 == Unsigned32 */ {ASN1_APL, SNMP_TIT, SNMP_TIMETICKS}, {ASN1_APL, SNMP_OPQ, SNMP_OPAQUE}, /* SNMPv2 data types and errors */ {ASN1_UNI, ASN1_BTS, SNMP_BITSTR}, {ASN1_APL, SNMP_C64, SNMP_COUNTER64}, {ASN1_CTX, SERR_NSO, SNMP_NOSUCHOBJECT}, {ASN1_CTX, SERR_NSI, SNMP_NOSUCHINSTANCE}, {ASN1_CTX, SERR_EOM, SNMP_ENDOFMIBVIEW}, {0, 0, -1}};static unsigned char snmp_tag_cls2syntax(unsigned int tag, unsigned int cls, unsigned short *syntax){ struct snmp_cnv *cnv; cnv = snmp_conv; while (cnv->syntax != -1) { if (cnv->tag == tag && cnv->class == cls) { *syntax = cnv->syntax; return 1; } cnv++; } return 0;}static unsigned char snmp_object_decode(struct asn1_ctx *ctx, struct snmp_object **obj){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -