snmp_msg.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /*
10  * SNMP Message Encoding Routines
11  *
12  * Complies with:
13  *
14  * RFC 1901: Introduction to Community-based SNMPv2
15  * RFC 1157: A Simple Network Management Protocol (SNMP)
16  *
17  */
18 /**********************************************************************
19  *
20  * Copyright 1997 by Carnegie Mellon University
21  *
22  * All Rights Reserved
23  *
24  * Permission to use, copy, modify, and distribute this software and its
25  * documentation for any purpose and without fee is hereby granted,
26  * provided that the above copyright notice appear in all copies and that
27  * both that copyright notice and this permission notice appear in
28  * supporting documentation, and that the name of CMU not be
29  * used in advertising or publicity pertaining to distribution of the
30  * software without specific, written prior permission.
31  *
32  * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
33  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
34  * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
35  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
36  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
37  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
38  * SOFTWARE.
39  *
40  * Author: Ryan Troll <ryan+@andrew.cmu.edu>
41  *
42  **********************************************************************/
43 
44 #include "squid.h"
45 
46 #if HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49 #if HAVE_STDLIB_H
50 #include <stdlib.h>
51 #endif
52 #if HAVE_SYS_TYPES_H
53 #include <sys/types.h>
54 #endif
55 #if HAVE_CTYPE_H
56 #include <ctype.h>
57 #endif
58 #if HAVE_GNUMALLOC_H
59 #include <gnumalloc.h>
60 #elif HAVE_MALLOC_H
61 #include <malloc.h>
62 #endif
63 #if HAVE_MEMORY_H
64 #include <memory.h>
65 #endif
66 #if HAVE_STRING_H
67 #include <string.h>
68 #endif
69 #if HAVE_STRINGS_H
70 #include <strings.h>
71 #endif
72 #if HAVE_BSTRING_H
73 #include <bstring.h>
74 #endif
75 #if HAVE_SYS_SOCKET_H
76 #include <sys/socket.h>
77 #endif
78 #if HAVE_NETINET_IN_H
79 #include <netinet/in.h>
80 #endif
81 #if HAVE_ARPA_INET_H
82 #include <arpa/inet.h>
83 #endif
84 #if HAVE_SYS_TIME_H
85 #include <sys/time.h>
86 #endif
87 #if HAVE_NETDB_H
88 #include <netdb.h>
89 #endif
90 #if HAVE_ASSERT_H
91 #include <assert.h>
92 #endif
93 
94 #include "asn1.h"
95 #include "snmp.h"
96 #include "snmp_msg.h"
97 #include "snmp_pdu.h"
98 #include "snmp_vars.h"
99 
100 /*
101  * RFC 1901: Introduction to Community-based SNMPv2
102  *
103  * Message ::=
104  * SEQUENCE {
105  * version INTEGER
106  * community OCTET STRING
107  * data
108  * }
109  *
110  * RFC 1157: A Simple Network Management Protocol (SNMP)
111  *
112  * Message ::=
113  * SEQUENCE {
114  * version INTEGER
115  * community OCTET STRING
116  * data
117  * }
118  *
119  */
120 
121 /* Encode a SNMP Message Header. Return a pointer to the beginning of the
122  * data.
123  */
124 
125 #define ASN_PARSE_ERROR(x) { return(x); }
126 
127 /* Encode an SNMP Message
128  *
129  * Returns a pointer to the end of the message, or NULL.
130  *
131  * *BufLenP (Second Argument) will contain the amount of space left
132  * in the buffer.
133  */
134 
135 u_char *
136 snmp_msg_Encode(u_char * Buffer, int *BufLenP,
137  u_char * Community, int CommLen,
138  int Version,
139  struct snmp_pdu *PDU)
140 {
141  u_char *bufp, *tmp;
142  u_char *PDUHeaderPtr, *VARHeaderPtr;
143  u_char *PDUDataStart, *VARDataStart;
144  u_char *MsgPtr;
145  int FakeArg = 1024;
146 
147  snmplib_debug(4, "Buffer=%p BufLenP=%p, buflen=%d\n", Buffer, BufLenP,
148  *BufLenP);
149  /* Header for the entire thing, with a false, large length */
150  bufp = asn_build_header(Buffer, BufLenP,
151  (u_char) (ASN_SEQUENCE |
153  (*BufLenP));
154  if (bufp == NULL) {
155  snmplib_debug(4, "snmp_msg_Encode:Error encoding SNMP Message Header (Header)!\n");
156  return (NULL);
157  }
158  MsgPtr = bufp;
159 
160  /* Version */
161  bufp = asn_build_int(bufp, BufLenP,
162  (u_char) (ASN_UNIVERSAL |
163  ASN_PRIMITIVE |
164  ASN_INTEGER),
165  (int *) (&Version), sizeof(Version));
166  if (bufp == NULL) {
167  snmplib_debug(4, "snmp_msg_Encode:Error encoding SNMP Message Header (Version)!\n");
168  return (NULL);
169  }
170  snmplib_debug(8, "snmp_msg_Encode: Encoding community (%s) (%d)\n", Community, CommLen);
171 
172  /* Community */
173  bufp = asn_build_string(bufp, BufLenP,
174  (u_char) (ASN_UNIVERSAL |
175  ASN_PRIMITIVE |
176  ASN_OCTET_STR),
177  Community, CommLen);
178  if (bufp == NULL) {
179  snmplib_debug(4, "snmp_msg_Encode:Error encoding SNMP Message Header (Community)!\n");
180  return (NULL);
181  }
182  /* Encode the rest. */
183 
184  /* A nice header for this PDU.
185  * Encoded with the wrong length. We'll fix it later.
186  */
187  snmplib_debug(8, "snmp_msg_Encode:Encoding PDU Header at 0x%p (fake len %d) (%d bytes so far)\n",
188  bufp, *BufLenP, *BufLenP);
189  PDUHeaderPtr = bufp;
190  bufp = asn_build_header(bufp, BufLenP,
191  (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
192  (*BufLenP));
193  if (bufp == NULL)
194  return (NULL);
195 
196  /* Encode this PDU. */
197  PDUDataStart = bufp;
198  bufp = snmp_pdu_encode(bufp, BufLenP, PDU);
199  if (bufp == NULL)
200  return (NULL); /* snmp_pdu_encode registered failure */
201 
202  VARHeaderPtr = bufp;
203  bufp = asn_build_header(bufp, BufLenP,
204  (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
205  FakeArg);
206  if (bufp == NULL)
207  return (NULL);
208  VARDataStart = bufp;
209 
210  /* And build the variables */
211  bufp = snmp_var_EncodeVarBind(bufp, BufLenP, PDU->variables, Version);
212  if (bufp == NULL)
213  return (NULL); /* snmp_var_EncodeVarBind registered failure */
214 
215  /* Cool. Now insert the appropriate lengths.
216  */
217 #if DEBUG_MSG_ENCODE
218  snmplib_debug(9, "Msg: Vars returned 0x%x. PDU Started at 0x%x\n",
219  bufp, PDUHeaderPtr);
220  snmplib_debug(9, "MSG: Entire PDU length is %d (0x%x - 0x%x)\n",
221  (int) (bufp - PDUDataStart), PDUHeaderPtr, bufp);
222 #endif
223  tmp = asn_build_header(PDUHeaderPtr, &FakeArg,
224  (u_char) PDU->command,
225  (int) (bufp - PDUDataStart));
226  /* Length of the PDU and Vars */
227  if (tmp == NULL)
228  return (NULL);
229 
230 #if DEBUG_MSG_ENCODE
231  snmplib_debug(9, "MSG: Entire message length is %d (0x%x - 0x%x)\n",
232  (int) (bufp - MsgPtr), MsgPtr, bufp);
233 #endif
234  tmp = asn_build_header(Buffer,
235  &FakeArg,
236  (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
237  (bufp - MsgPtr)); /* Length of everything */
238  if (tmp == NULL)
239  return (NULL);
240 
241  tmp = asn_build_header(VARHeaderPtr,
242  &FakeArg,
243  (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
244  (bufp - VARDataStart)); /* Length of everything */
245  if (tmp == NULL)
246  return (NULL);
247 
248  *BufLenP = (bufp - Buffer);
249  return (u_char *) bufp;
250 }
251 
252 /**********************************************************************/
253 
254 u_char *
255 snmp_msg_Decode(u_char * Packet, int *PacketLenP,
256  u_char * Community, int *CommLenP,
257  int *Version, struct snmp_pdu * PDU)
258 {
259  u_char *bufp;
260  u_char type;
261 
262  bufp = asn_parse_header(Packet, PacketLenP, &type);
263  if (bufp == NULL) {
264  snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Header)!\n");
266  }
267  if (type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
268  snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Header)!\n");
270  }
271  bufp = asn_parse_int(bufp, PacketLenP,
272  &type,
273  (int *) Version, sizeof(*Version));
274  if (bufp == NULL) {
275  snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Version)!\n");
277  }
278  int communityBufferLimit = *CommLenP;
279 
280  bufp = asn_parse_string(bufp, PacketLenP, &type, Community, CommLenP);
281  if (bufp == NULL) {
282  snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Community)!\n");
284  }
285 
286  if (*CommLenP == communityBufferLimit) {
287  snmplib_debug(4, "snmp_msg_Decode:Cannot zero-terminate a %d byte-long Community value\n", *CommLenP);
289  }
290  assert(*CommLenP >= 0);
291  assert(*CommLenP < communityBufferLimit);
292  Community[*CommLenP] = '\0';
293 
294  if (memchr(Community, '\0', (size_t)*CommLenP)) {
295  snmplib_debug(4, "snmp_msg_Decode:Community contained an unsupported ASCII nul character\n");
297  }
298 
299  if ((*Version != SNMP_VERSION_1) &&
300  (*Version != SNMP_VERSION_2)) {
301 
302  /* Don't know how to handle this one. */
303  snmplib_debug(4, "snmp_msg_Decode:Unable to parse Version %u\n", *Version);
304  snmplib_debug(4, "snmp_msg_Decode:Continuing anyway\n");
305  }
306  /* Now that we know the header, decode the PDU */
307 
308  /* XXXXX -- More than one PDU? */
309  bufp = snmp_pdu_decode(bufp, PacketLenP, PDU);
310  if (bufp == NULL)
311  /* snmp_pdu_decode registered failure */
312  return (NULL);
313 
314  bufp = snmp_var_DecodeVarBind(bufp, PacketLenP, &(PDU->variables), *Version);
315  if (bufp == NULL)
316  /* snmp_var_DecodeVarBind registered failure */
317  return (NULL);
318 
319  return (u_char *) bufp;
320 }
321 
#define SNMP_VERSION_1
Definition: snmp_msg.h:40
u_char * snmp_var_DecodeVarBind(u_char *, int *, struct variable_list **, int)
Definition: snmp_vars.c:368
#define ASN_OCTET_STR
Definition: asn1.h:54
u_char * asn_build_int(u_char *, int *, u_char, int *, int)
Definition: asn1.c:245
u_char * asn_build_header(u_char *, int *, u_char, int)
Definition: asn1.c:93
#define ASN_PARSE_ERROR(x)
Definition: snmp_msg.c:125
u_char * snmp_pdu_encode(u_char *, int *, struct snmp_pdu *)
Definition: snmp_pdu.c:350
#define NULL
Definition: types.h:145
struct variable_list * variables
Definition: snmp_pdu.h:86
u_char * snmp_msg_Encode(u_char *Buffer, int *BufLenP, u_char *Community, int CommLen, int Version, struct snmp_pdu *PDU)
Definition: snmp_msg.c:136
u_char * asn_parse_string(u_char *, int *, u_char *, u_char *, int *)
Definition: asn1.c:387
int command
Definition: snmp_pdu.h:75
#define ASN_INTEGER
Definition: asn1.h:52
u_char * asn_parse_header(u_char *, int *, u_char *)
Definition: asn1.c:470
#define assert(EX)
Definition: assert.h:17
u_char * asn_build_string(u_char *, int *, u_char, u_char *, int)
Definition: asn1.c:433
u_char * snmp_msg_Decode(u_char *Packet, int *PacketLenP, u_char *Community, int *CommLenP, int *Version, struct snmp_pdu *PDU)
Definition: snmp_msg.c:255
#define SNMP_VERSION_2
Definition: snmp_msg.h:41
#define ASN_SEQUENCE
Definition: asn1.h:57
int type
Definition: parse.h:56
u_char * snmp_pdu_decode(u_char *, int *, struct snmp_pdu *)
Definition: snmp_pdu.c:486
SQUIDCEXTERN void snmplib_debug(int, const char *,...) PRINTF_FORMAT_ARG2
Definition: snmplib_debug.c:21
#define ASN_CONSTRUCTOR
Definition: asn1.h:66
#define ASN_UNIVERSAL
Definition: asn1.h:60
u_char * asn_parse_int(u_char *, int *, u_char *, int *, int)
Definition: asn1.c:114
#define ASN_PRIMITIVE
Definition: asn1.h:65
u_char * snmp_var_EncodeVarBind(u_char *, int *, struct variable_list *, int)
Definition: snmp_vars.c:259

 

Introduction

Documentation

Support

Miscellaneous