Squid Web Cache master
Loading...
Searching...
No Matches
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
135u_char *
136snmp_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 |
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 |
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
254u_char *
255snmp_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
u_char * asn_build_header(u_char *, int *, u_char, int)
Definition asn1.c:93
#define ASN_CONSTRUCTOR
Definition asn1.h:66
#define ASN_SEQUENCE
Definition asn1.h:57
#define ASN_OCTET_STR
Definition asn1.h:54
#define ASN_PRIMITIVE
Definition asn1.h:65
#define ASN_INTEGER
Definition asn1.h:52
u_char * asn_parse_int(u_char *, int *, u_char *, int *, int)
Definition asn1.c:114
#define ASN_UNIVERSAL
Definition asn1.h:60
u_char * asn_parse_string(u_char *, int *, u_char *, u_char *, int *)
Definition asn1.c:387
u_char * asn_build_int(u_char *, int *, u_char, int *, int)
Definition asn1.c:245
u_char * asn_parse_header(u_char *, int *, u_char *)
Definition asn1.c:470
u_char * asn_build_string(u_char *, int *, u_char, u_char *, int)
Definition asn1.c:433
#define assert(EX)
Definition assert.h:17
SQUIDCEXTERN void snmplib_debug(int, const char *,...) PRINTF_FORMAT_ARG2
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 ASN_PARSE_ERROR(x)
Definition snmp_msg.c:125
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
#define SNMP_VERSION_2
Definition snmp_msg.h:41
#define SNMP_VERSION_1
Definition snmp_msg.h:40
u_char * snmp_pdu_encode(u_char *, int *, struct snmp_pdu *)
Definition snmp_pdu.c:350
u_char * snmp_pdu_decode(u_char *, int *, struct snmp_pdu *)
Definition snmp_pdu.c:486
u_char * snmp_var_EncodeVarBind(u_char *, int *, struct variable_list *, int)
Definition snmp_vars.c:259
u_char * snmp_var_DecodeVarBind(u_char *, int *, struct variable_list **, int)
Definition snmp_vars.c:368
int command
Definition snmp_pdu.h:51
struct variable_list * variables
Definition snmp_pdu.h:62
#define NULL
Definition types.h:145