]> git.ipfire.org Git - thirdparty/squid.git/blob - lib/snmplib/snmp_msg.c
merge from trunk
[thirdparty/squid.git] / lib / 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 #if HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41 #if HAVE_STDLIB_H
42 #include <stdlib.h>
43 #endif
44 #if HAVE_SYS_TYPES_H
45 #include <sys/types.h>
46 #endif
47 #if HAVE_CTYPE_H
48 #include <ctype.h>
49 #endif
50 #if HAVE_GNUMALLOC_H
51 #include <gnumalloc.h>
52 #elif HAVE_MALLOC_H
53 #include <malloc.h>
54 #endif
55 #if HAVE_MEMORY_H
56 #include <memory.h>
57 #endif
58 #if HAVE_STRING_H
59 #include <string.h>
60 #endif
61 #if HAVE_STRINGS_H
62 #include <strings.h>
63 #endif
64 #if HAVE_BSTRING_H
65 #include <bstring.h>
66 #endif
67 #if HAVE_SYS_SOCKET_H
68 #include <sys/socket.h>
69 #endif
70 #if HAVE_NETINET_IN_H
71 #include <netinet/in.h>
72 #endif
73 #if HAVE_ARPA_INET_H
74 #include <arpa/inet.h>
75 #endif
76 #if HAVE_SYS_TIME_H
77 #include <sys/time.h>
78 #endif
79 #if HAVE_NETDB_H
80 #include <netdb.h>
81 #endif
82
83 #include "asn1.h"
84 #include "snmp.h"
85 #include "snmp_msg.h"
86 #include "snmp_pdu.h"
87 #include "snmp_vars.h"
88
89 /*
90 * RFC 1901: Introduction to Community-based SNMPv2
91 *
92 * Message ::=
93 * SEQUENCE {
94 * version INTEGER
95 * community OCTET STRING
96 * data
97 * }
98 *
99 * RFC 1157: A Simple Network Management Protocol (SNMP)
100 *
101 * Message ::=
102 * SEQUENCE {
103 * version INTEGER
104 * community OCTET STRING
105 * data
106 * }
107 *
108 */
109
110 /* Encode a SNMP Message Header. Return a pointer to the beginning of the
111 * data.
112 */
113
114 #define ASN_PARSE_ERROR(x) { return(x); }
115
116 /* Encode an SNMP Message
117 *
118 * Returns a pointer to the end of the message, or NULL.
119 *
120 * *BufLenP (Second Argument) will contain the amount of space left
121 * in the buffer.
122 */
123
124 u_char *
125 snmp_msg_Encode(u_char * Buffer, int *BufLenP,
126 u_char * Community, int CommLen,
127 int Version,
128 struct snmp_pdu *PDU)
129 {
130 u_char *bufp, *tmp;
131 u_char *PDUHeaderPtr, *VARHeaderPtr;
132 u_char *PDUDataStart, *VARDataStart;
133 u_char *MsgPtr;
134 int FakeArg = 1024;
135
136 snmplib_debug(4, "Buffer=%p BufLenP=%p, buflen=%d\n", Buffer, BufLenP,
137 *BufLenP);
138 /* Header for the entire thing, with a false, large length */
139 bufp = asn_build_header(Buffer, BufLenP,
140 (u_char) (ASN_SEQUENCE |
141 ASN_CONSTRUCTOR),
142 (*BufLenP));
143 if (bufp == NULL) {
144 snmplib_debug(4, "snmp_msg_Encode:Error encoding SNMP Message Header (Header)!\n");
145 return (NULL);
146 }
147 MsgPtr = bufp;
148
149 /* Version */
150 bufp = asn_build_int(bufp, BufLenP,
151 (u_char) (ASN_UNIVERSAL |
152 ASN_PRIMITIVE |
153 ASN_INTEGER),
154 (int *) (&Version), sizeof(Version));
155 if (bufp == NULL) {
156 snmplib_debug(4, "snmp_msg_Encode:Error encoding SNMP Message Header (Version)!\n");
157 return (NULL);
158 }
159 snmplib_debug(8, "snmp_msg_Encode: Encoding community (%s) (%d)\n", Community, CommLen);
160
161 /* Community */
162 bufp = asn_build_string(bufp, BufLenP,
163 (u_char) (ASN_UNIVERSAL |
164 ASN_PRIMITIVE |
165 ASN_OCTET_STR),
166 Community, CommLen);
167 if (bufp == NULL) {
168 snmplib_debug(4, "snmp_msg_Encode:Error encoding SNMP Message Header (Community)!\n");
169 return (NULL);
170 }
171 /* Encode the rest. */
172
173 /* A nice header for this PDU.
174 * Encoded with the wrong length. We'll fix it later.
175 */
176 snmplib_debug(8, "snmp_msg_Encode:Encoding PDU Header at 0x%p (fake len %d) (%d bytes so far)\n",
177 bufp, *BufLenP, *BufLenP);
178 PDUHeaderPtr = bufp;
179 bufp = asn_build_header(bufp, BufLenP,
180 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
181 (*BufLenP));
182 if (bufp == NULL)
183 return (NULL);
184
185 /* Encode this PDU. */
186 PDUDataStart = bufp;
187 bufp = snmp_pdu_encode(bufp, BufLenP, PDU);
188 if (bufp == NULL)
189 return (NULL); /* snmp_pdu_encode registered failure */
190
191 VARHeaderPtr = bufp;
192 bufp = asn_build_header(bufp, BufLenP,
193 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
194 FakeArg);
195 if (bufp == NULL)
196 return (NULL);
197 VARDataStart = bufp;
198
199 /* And build the variables */
200 bufp = snmp_var_EncodeVarBind(bufp, BufLenP, PDU->variables, Version);
201 if (bufp == NULL)
202 return (NULL); /* snmp_var_EncodeVarBind registered failure */
203
204 /* Cool. Now insert the appropriate lengths.
205 */
206 #if DEBUG_MSG_ENCODE
207 snmplib_debug(9, "Msg: Vars returned 0x%x. PDU Started at 0x%x\n",
208 bufp, PDUHeaderPtr);
209 snmplib_debug(9, "MSG: Entire PDU length is %d (0x%x - 0x%x)\n",
210 (int) (bufp - PDUDataStart), PDUHeaderPtr, bufp);
211 #endif
212 tmp = asn_build_header(PDUHeaderPtr, &FakeArg,
213 (u_char) PDU->command,
214 (int) (bufp - PDUDataStart));
215 /* Length of the PDU and Vars */
216 if (tmp == NULL)
217 return (NULL);
218
219 #if DEBUG_MSG_ENCODE
220 snmplib_debug(9, "MSG: Entire message length is %d (0x%x - 0x%x)\n",
221 (int) (bufp - MsgPtr), MsgPtr, bufp);
222 #endif
223 tmp = asn_build_header(Buffer,
224 &FakeArg,
225 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
226 (bufp - MsgPtr)); /* Length of everything */
227 if (tmp == NULL)
228 return (NULL);
229
230 tmp = asn_build_header(VARHeaderPtr,
231 &FakeArg,
232 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
233 (bufp - VARDataStart)); /* Length of everything */
234 if (tmp == NULL)
235 return (NULL);
236
237 *BufLenP = (bufp - Buffer);
238 return (u_char *) bufp;
239 }
240
241 /**********************************************************************/
242
243 u_char *
244 snmp_msg_Decode(u_char * Packet, int *PacketLenP,
245 u_char * Community, int *CommLenP,
246 int *Version, struct snmp_pdu * PDU)
247 {
248 u_char *bufp;
249 u_char type;
250
251 bufp = asn_parse_header(Packet, PacketLenP, &type);
252 if (bufp == NULL) {
253 snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Header)!\n");
254 ASN_PARSE_ERROR(NULL);
255 }
256 if (type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
257 snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Header)!\n");
258 ASN_PARSE_ERROR(NULL);
259 }
260 bufp = asn_parse_int(bufp, PacketLenP,
261 &type,
262 (int *) Version, sizeof(*Version));
263 if (bufp == NULL) {
264 snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Version)!\n");
265 ASN_PARSE_ERROR(NULL);
266 }
267 bufp = asn_parse_string(bufp, PacketLenP, &type, Community, CommLenP);
268 if (bufp == NULL) {
269 snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Community)!\n");
270 ASN_PARSE_ERROR(NULL);
271 }
272 Community[*CommLenP] = '\0';
273
274 if ((*Version != SNMP_VERSION_1) &&
275 (*Version != SNMP_VERSION_2)) {
276
277 /* Don't know how to handle this one. */
278 snmplib_debug(4, "snmp_msg_Decode:Unable to parse Version %u\n", *Version);
279 snmplib_debug(4, "snmp_msg_Decode:Continuing anyway\n");
280 }
281 /* Now that we know the header, decode the PDU */
282
283 /* XXXXX -- More than one PDU? */
284 bufp = snmp_pdu_decode(bufp, PacketLenP, PDU);
285 if (bufp == NULL)
286 /* snmp_pdu_decode registered failure */
287 return (NULL);
288
289 bufp = snmp_var_DecodeVarBind(bufp, PacketLenP, &(PDU->variables), *Version);
290 if (bufp == NULL)
291 /* snmp_var_DecodeVarBind registered failure */
292 return (NULL);
293
294 return (u_char *) bufp;
295 }