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