⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nf_nat_snmp_basic.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	unsigned int cls, con, tag, len, idlen;	unsigned short type;	unsigned char *eoc, *end, *p;	unsigned long *lp, *id;	unsigned long ul;	long l;	*obj = NULL;	id = NULL;	if (!asn1_header_decode(ctx, &eoc, &cls, &con, &tag))		return 0;	if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ)		return 0;	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, &id, &idlen))		return 0;	if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) {		kfree(id);		return 0;	}	if (con != ASN1_PRI) {		kfree(id);		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);			if (!asn1_long_decode(ctx, end, &l)) {				kfree(id);				return 0;			}			*obj = kmalloc(sizeof(struct snmp_object) + len,				       GFP_ATOMIC);			if (*obj == NULL) {				kfree(id);				if (net_ratelimit())					printk("OOM in bsalg (%d)\n", __LINE__);				return 0;			}			(*obj)->syntax.l[0] = l;			break;		case SNMP_OCTETSTR:		case SNMP_OPAQUE:			if (!asn1_octets_decode(ctx, end, &p, &len)) {				kfree(id);				return 0;			}			*obj = kmalloc(sizeof(struct snmp_object) + len,				       GFP_ATOMIC);			if (*obj == NULL) {				kfree(id);				if (net_ratelimit())					printk("OOM in bsalg (%d)\n", __LINE__);				return 0;			}			memcpy((*obj)->syntax.c, p, len);			kfree(p);			break;		case SNMP_NULL:		case SNMP_NOSUCHOBJECT:		case SNMP_NOSUCHINSTANCE:		case SNMP_ENDOFMIBVIEW:			len = 0;			*obj = kmalloc(sizeof(struct snmp_object), GFP_ATOMIC);			if (*obj == NULL) {				kfree(id);				if (net_ratelimit())					printk("OOM in bsalg (%d)\n", __LINE__);				return 0;			}			if (!asn1_null_decode(ctx, end)) {				kfree(id);				kfree(*obj);				*obj = NULL;				return 0;			}			break;		case SNMP_OBJECTID:			if (!asn1_oid_decode(ctx, end, (unsigned long **)&lp, &len)) {				kfree(id);				return 0;			}			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__);				return 0;			}			memcpy((*obj)->syntax.ul, lp, len);			kfree(lp);			break;		case SNMP_IPADDR:			if (!asn1_octets_decode(ctx, end, &p, &len)) {				kfree(id);				return 0;			}			if (len != 4) {				kfree(p);				kfree(id);				return 0;			}			*obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC);			if (*obj == NULL) {				kfree(p);				kfree(id);				if (net_ratelimit())					printk("OOM in bsalg (%d)\n", __LINE__);				return 0;			}			memcpy((*obj)->syntax.uc, p, len);			kfree(p);			break;		case SNMP_COUNTER:		case SNMP_GAUGE:		case SNMP_TIMETICKS:			len = sizeof(unsigned long);			if (!asn1_ulong_decode(ctx, end, &ul)) {				kfree(id);				return 0;			}			*obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC);			if (*obj == NULL) {				kfree(id);				if (net_ratelimit())					printk("OOM in bsalg (%d)\n", __LINE__);				return 0;			}			(*obj)->syntax.ul[0] = ul;			break;		default:			kfree(id);			return 0;	}	(*obj)->syntax_len = len;	(*obj)->type = type;	(*obj)->id = id;	(*obj)->id_len = idlen;	if (!asn1_eoc_decode(ctx, eoc)) {		kfree(id);		kfree(*obj);		*obj = NULL;		return 0;	}	return 1;}static unsigned char snmp_request_decode(struct asn1_ctx *ctx,					 struct snmp_request *request){	unsigned int cls, con, tag;	unsigned char *end;	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_ulong_decode(ctx, end, &request->id))		return 0;	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, &request->error_status))		return 0;	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, &request->error_index))		return 0;	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,				      __sum16 *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_addr_free:	kfree((unsigned long *)trap->ip_address);err_id_free:	kfree(trap->id);	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,			     __sum16 *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);		if (ret) {			kfree(trap.id);			kfree((unsigned long *)trap.ip_address);		} else			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 nf_conn *ct,			  enum ip_conntrack_info ctinfo,			  struct sk_buff *skb){	struct iphdr *iph = ip_hdr(skb);	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);	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[dir].tuple.src.u3.ip);		map.to = NOCT1(&ct->tuplehash[!dir].tuple.dst.u3.ip);	} else {		/* DNAT replies */		map.from = NOCT1(&ct->tuplehash[dir].tuple.src.u3.ip);		map.to = NOCT1(&ct->tuplehash[!dir].tuple.dst.u3.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 *skb, unsigned int protoff,		struct nf_conn *ct,		enum ip_conntrack_info ctinfo){	int dir = CTINFO2DIR(ctinfo);	unsigned int ret;	struct iphdr *iph = ip_hdr(skb);	struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl);	/* 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;	/*	 * 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) != skb->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(skb, skb->len))		return NF_DROP;	spin_lock_bh(&snmp_lock);	ret = snmp_translate(ct, ctinfo, skb);	spin_unlock_bh(&snmp_lock);	return ret;}static struct nf_conntrack_helper snmp_helper __read_mostly = {	.max_expected		= 0,	.timeout		= 180,	.me			= THIS_MODULE,	.help			= help,	.name			= "snmp",	.tuple.src.l3num	= AF_INET,	.tuple.src.u.udp.port	= __constant_htons(SNMP_PORT),	.tuple.dst.protonum	= IPPROTO_UDP,};static struct nf_conntrack_helper snmp_trap_helper __read_mostly = {	.max_expected		= 0,	.timeout		= 180,	.me			= THIS_MODULE,	.help			= help,	.name			= "snmp_trap",	.tuple.src.l3num	= AF_INET,	.tuple.src.u.udp.port	= __constant_htons(SNMP_TRAP_PORT),	.tuple.dst.protonum	= IPPROTO_UDP,};/***************************************************************************** * * Module stuff. * *****************************************************************************/static int __init nf_nat_snmp_basic_init(void){	int ret = 0;	ret = nf_conntrack_helper_register(&snmp_helper);	if (ret < 0)		return ret;	ret = nf_conntrack_helper_register(&snmp_trap_helper);	if (ret < 0) {		nf_conntrack_helper_unregister(&snmp_helper);		return ret;	}	return ret;}static void __exit nf_nat_snmp_basic_fini(void){	nf_conntrack_helper_unregister(&snmp_helper);	nf_conntrack_helper_unregister(&snmp_trap_helper);}module_init(nf_nat_snmp_basic_init);module_exit(nf_nat_snmp_basic_fini);module_param(debug, int, 0600);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -