]> git.ipfire.org Git - thirdparty/squid.git/blob - snmplib/snmp_msg.c
Enable source-formatting tools to collapse multiple whitelines in the source to one.
[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 /*
93 * RFC 1901: Introduction to Community-based SNMPv2
94 *
95 * Message ::=
96 * SEQUENCE {
97 * version INTEGER
98 * community OCTET STRING
99 * data
100 * }
101 *
102 * RFC 1157: A Simple Network Management Protocol (SNMP)
103 *
104 * Message ::=
105 * SEQUENCE {
106 * version INTEGER
107 * community OCTET STRING
108 * data
109 * }
110 *
111 */
112
113 /* Encode a SNMP Message Header. Return a pointer to the beginning of the
114 * data.
115 */
116
117 #define ASN_PARSE_ERROR(x) { return(x); }
118
119 /* Encode an SNMP Message
120 *
121 * Returns a pointer to the end of the message, or NULL.
122 *
123 * *BufLenP (Second Argument) will contain the amount of space left
124 * in the buffer.
125 */
126
127 u_char *
128 snmp_msg_Encode(u_char * Buffer, int *BufLenP,
129 u_char * Community, int CommLen,
130 int Version,
131 struct snmp_pdu *PDU)
132 {
133 u_char *bufp, *tmp;
134 u_char *PDUHeaderPtr, *VARHeaderPtr;
135 u_char *PDUDataStart, *VARDataStart;
136 u_char *MsgPtr;
137 int FakeArg = 1024;
138
139 snmplib_debug(4, "Buffer=%p BufLenP=%p, buflen=%d\n", Buffer, BufLenP,
140 *BufLenP);
141 /* Header for the entire thing, with a false, large length */
142 bufp = asn_build_header(Buffer, BufLenP,
143 (u_char) (ASN_SEQUENCE |
144 ASN_CONSTRUCTOR),
145 (*BufLenP));
146 if (bufp == NULL) {
147 snmplib_debug(4, "snmp_msg_Encode:Error encoding SNMP Message Header (Header)!\n");
148 return (NULL);
149 }
150 MsgPtr = bufp;
151
152 /* Version */
153 bufp = asn_build_int(bufp, BufLenP,
154 (u_char) (ASN_UNIVERSAL |
155 ASN_PRIMITIVE |
156 ASN_INTEGER),
157 (int *) (&Version), sizeof(Version));
158 if (bufp == NULL) {
159 snmplib_debug(4, "snmp_msg_Encode:Error encoding SNMP Message Header (Version)!\n");
160 return (NULL);
161 }
162 snmplib_debug(8, "snmp_msg_Encode: Encoding community (%s) (%d)\n", Community, CommLen);
163
164 /* Community */
165 bufp = asn_build_string(bufp, BufLenP,
166 (u_char) (ASN_UNIVERSAL |
167 ASN_PRIMITIVE |
168 ASN_OCTET_STR),
169 Community, CommLen);
170 if (bufp == NULL) {
171 snmplib_debug(4, "snmp_msg_Encode:Error encoding SNMP Message Header (Community)!\n");
172 return (NULL);
173 }
174 /* Encode the rest. */
175
176 /* A nice header for this PDU.
177 * Encoded with the wrong length. We'll fix it later.
178 */
179 snmplib_debug(8, "snmp_msg_Encode:Encoding PDU Header at 0x%p (fake len %d) (%d bytes so far)\n",
180 bufp, *BufLenP, *BufLenP);
181 PDUHeaderPtr = bufp;
182 bufp = asn_build_header(bufp, BufLenP,
183 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
184 (*BufLenP));
185 if (bufp == NULL)
186 return (NULL);
187
188 /* Encode this PDU. */
189 PDUDataStart = bufp;
190 bufp = snmp_pdu_encode(bufp, BufLenP, PDU);
191 if (bufp == NULL)
192 return (NULL); /* snmp_pdu_encode registered failure */
193
194 VARHeaderPtr = bufp;
195 bufp = asn_build_header(bufp, BufLenP,
196 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
197 FakeArg);
198 if (bufp == NULL)
199 return (NULL);
200 VARDataStart = bufp;
201
202 /* And build the variables */
203 bufp = snmp_var_EncodeVarBind(bufp, BufLenP, PDU->variables, Version);
204 if (bufp == NULL)
205 return (NULL); /* snmp_var_EncodeVarBind registered failure */
206
207 /* Cool. Now insert the appropriate lengths.
208 */
209 #if DEBUG_MSG_ENCODE
210 snmplib_debug(9, "Msg: Vars returned 0x%x. PDU Started at 0x%x\n",
211 bufp, PDUHeaderPtr);
212 snmplib_debug(9, "MSG: Entire PDU length is %d (0x%x - 0x%x)\n",
213 (int) (bufp - PDUDataStart), PDUHeaderPtr, bufp);
214 #endif
215 tmp = asn_build_header(PDUHeaderPtr, &FakeArg,
216 (u_char) PDU->command,
217 (int) (bufp - PDUDataStart));
218 /* Length of the PDU and Vars */
219 if (tmp == NULL)
220 return (NULL);
221
222 #if DEBUG_MSG_ENCODE
223 snmplib_debug(9, "MSG: Entire message length is %d (0x%x - 0x%x)\n",
224 (int) (bufp - MsgPtr), MsgPtr, bufp);
225 #endif
226 tmp = asn_build_header(Buffer,
227 &FakeArg,
228 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
229 (bufp - MsgPtr)); /* Length of everything */
230 if (tmp == NULL)
231 return (NULL);
232
233 tmp = asn_build_header(VARHeaderPtr,
234 &FakeArg,
235 (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
236 (bufp - VARDataStart)); /* Length of everything */
237 if (tmp == NULL)
238 return (NULL);
239
240 *BufLenP = (bufp - Buffer);
241 return (u_char *) bufp;
242 }
243
244 /**********************************************************************/
245
246 u_char *
247 snmp_msg_Decode(u_char * Packet, int *PacketLenP,
248 u_char * Community, int *CommLenP,
249 int *Version, struct snmp_pdu * PDU)
250 {
251 u_char *bufp;
252 u_char type;
253
254 bufp = asn_parse_header(Packet, PacketLenP, &type);
255 if (bufp == NULL) {
256 snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Messsage Header (Header)!\n");
257 ASN_PARSE_ERROR(NULL);
258 }
259 if (type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
260 snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Messsage Header (Header)!\n");
261 ASN_PARSE_ERROR(NULL);
262 }
263 bufp = asn_parse_int(bufp, PacketLenP,
264 &type,
265 (int *) Version, sizeof(*Version));
266 if (bufp == NULL) {
267 snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Messsage Header (Version)!\n");
268 ASN_PARSE_ERROR(NULL);
269 }
270 bufp = asn_parse_string(bufp, PacketLenP, &type, Community, CommLenP);
271 if (bufp == NULL) {
272 snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Messsage Header (Community)!\n");
273 ASN_PARSE_ERROR(NULL);
274 }
275 Community[*CommLenP] = '\0';
276
277 if ((*Version != SNMP_VERSION_1) &&
278 (*Version != SNMP_VERSION_2)) {
279
280 /* Don't know how to handle this one. */
281 snmplib_debug(4, "snmp_msg_Decode:Unable to parse Version %u\n", *Version);
282 snmplib_debug(4, "snmp_msg_Decode:Continuing anyway\n");
283 }
284 /* Now that we know the header, decode the PDU */
285
286 /* XXXXX -- More than one PDU? */
287 bufp = snmp_pdu_decode(bufp, PacketLenP, PDU);
288 if (bufp == NULL)
289 /* snmp_pdu_decode registered failure */
290 return (NULL);
291
292 bufp = snmp_var_DecodeVarBind(bufp, PacketLenP, &(PDU->variables), *Version);
293 if (bufp == NULL)
294 /* snmp_var_DecodeVarBind registered failure */
295 return (NULL);
296
297 return (u_char *) bufp;
298 }