]> The Tcpdump Group git mirrors - libpcap/blob - rpcap-protocol.c
Redo the message processing in the server.
[libpcap] / rpcap-protocol.c
1 /*
2 * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy)
3 * Copyright (c) 2005 - 2008 CACE Technologies, Davis (California)
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the Politecnico di Torino, CACE Technologies
16 * nor the names of its contributors may be used to endorse or promote
17 * products derived from this software without specific prior written
18 * permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37
38 #include <string.h> /* for strlen(), ... */
39 #include <stdlib.h> /* for malloc(), free(), ... */
40 #include <stdarg.h> /* for functions with variable number of arguments */
41 #include <errno.h> /* for the errno variable */
42 #include "sockutils.h"
43 #include "portability.h"
44 #include "rpcap-protocol.h"
45 #include <pcap/pcap.h>
46
47 /*
48 * This file contains functions used both by the rpcap client and the
49 * rpcap daemon.
50 */
51
52 /*
53 * This function sends a RPCAP error to our peer.
54 *
55 * It has to be called when the main program detects an error.
56 * It will send to our peer the 'buffer' specified by the user.
57 * This function *does not* request a RPCAP CLOSE connection. A CLOSE
58 * command must be sent explicitly by the program, since we do not know
59 * whether the error can be recovered in some way or if it is a
60 * non-recoverable one.
61 *
62 * \param sock: the socket we are currently using.
63 *
64 * \param error: an user-allocated (and '0' terminated) buffer that contains
65 * the error description that has to be transmitted to our peer. The
66 * error message cannot be longer than PCAP_ERRBUF_SIZE.
67 *
68 * \param errcode: a integer which tells the other party the type of error
69 * we had; currently is is not too much used.
70 *
71 * \param errbuf: a pointer to a user-allocated buffer (of size
72 * PCAP_ERRBUF_SIZE) that will contain the error message (in case there
73 * is one). It could be network problem.
74 *
75 * \return '0' if everything is fine, '-1' if some errors occurred. The
76 * error message is returned in the 'errbuf' variable.
77 */
78 int
79 rpcap_senderror(SOCKET sock, char *error, unsigned short errcode, char *errbuf)
80 {
81 char sendbuf[RPCAP_NETBUF_SIZE]; /* temporary buffer in which data to be sent is buffered */
82 int sendbufidx = 0; /* index which keeps the number of bytes currently buffered */
83 uint16 length;
84
85 length = (uint16)strlen(error);
86
87 if (length > PCAP_ERRBUF_SIZE)
88 length = PCAP_ERRBUF_SIZE;
89
90 rpcap_createhdr((struct rpcap_header *) sendbuf, RPCAP_MSG_ERROR, errcode, length);
91
92 if (sock_bufferize(NULL, sizeof(struct rpcap_header), NULL, &sendbufidx,
93 RPCAP_NETBUF_SIZE, SOCKBUF_CHECKONLY, errbuf, PCAP_ERRBUF_SIZE))
94 return -1;
95
96 if (sock_bufferize(error, length, sendbuf, &sendbufidx,
97 RPCAP_NETBUF_SIZE, SOCKBUF_BUFFERIZE, errbuf, PCAP_ERRBUF_SIZE))
98 return -1;
99
100 if (sock_send(sock, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE))
101 return -1;
102
103 return 0;
104 }
105
106 /*
107 * This function fills in a structure of type rpcap_header.
108 *
109 * It is provided just because the creation of an rpcap header is a common
110 * task. It accepts all the values that appears into an rpcap_header, and
111 * it puts them in place using the proper hton() calls.
112 *
113 * \param header: a pointer to a user-allocated buffer which will contain
114 * the serialized header, ready to be sent on the network.
115 *
116 * \param type: a value (in the host by order) which will be placed into the
117 * header.type field and that represents the type of the current message.
118 *
119 * \param value: a value (in the host by order) which will be placed into
120 * the header.value field and that has a message-dependent meaning.
121 *
122 * \param length: a value (in the host by order) which will be placed into
123 * the header.length field, representing the payload length of the message.
124 *
125 * \return Nothing. The serialized header is returned into the 'header'
126 * variable.
127 */
128 void
129 rpcap_createhdr(struct rpcap_header *header, uint8 type, uint16 value, uint32 length)
130 {
131 memset(header, 0, sizeof(struct rpcap_header));
132
133 header->ver = RPCAP_VERSION;
134 header->type = type;
135 header->value = htons(value);
136 header->plen = htonl(length);
137 }
138
139 /*
140 * Convert a message type to a string containing the type name.
141 */
142 static const char *requests[] =
143 {
144 NULL, /* not a valid message type */
145 "RPCAP_MSG_ERROR",
146 "RPCAP_MSG_FINDALLIF_REQ",
147 "RPCAP_MSG_OPEN_REQ",
148 "RPCAP_MSG_STARTCAP_REQ",
149 "RPCAP_MSG_UPDATEFILTER_REQ",
150 "RPCAP_MSG_CLOSE",
151 "RPCAP_MSG_PACKET",
152 "RPCAP_MSG_AUTH_REQ",
153 "RPCAP_MSG_STATS_REQ",
154 "RPCAP_MSG_ENDCAP_REQ",
155 "RPCAP_MSG_SETSAMPLING_REQ",
156 };
157 #define NUM_REQ_TYPES (sizeof requests / sizeof requests[0])
158
159 static const char *replies[] =
160 {
161 NULL,
162 NULL, /* this would be a reply to RPCAP_MSG_ERROR */
163 "RPCAP_MSG_FINDALLIF_REPLY",
164 "RPCAP_MSG_OPEN_REPLY",
165 "RPCAP_MSG_STARTCAP_REPLY",
166 "RPCAP_MSG_UPDATEFILTER_REPLY",
167 NULL, /* this would be a reply to RPCAP_MSG_CLOSE */
168 NULL, /* this would be a reply to RPCAP_MSG_PACKET */
169 "RPCAP_MSG_AUTH_REPLY",
170 "RPCAP_MSG_STATS_REPLY",
171 "RPCAP_MSG_ENDCAP_REPLY",
172 "RPCAP_MSG_SETSAMPLING_REPLY",
173 };
174 #define NUM_REPLY_TYPES (sizeof replies / sizeof replies[0])
175
176 const char *
177 rpcap_msg_type_string(uint8 type)
178 {
179 if (type & RPCAP_MSG_IS_REPLY) {
180 type &= ~RPCAP_MSG_IS_REPLY;
181 if (type >= NUM_REPLY_TYPES)
182 return NULL;
183 return replies[type];
184 } else {
185 if (type > NUM_REQ_TYPES)
186 return NULL;
187 return requests[type];
188 }
189 }
190
191 /*
192 * This function checks whether the header of the received message is correct.
193 *
194 * It is a way to easily check if the message received, in a certain state
195 * of the RPCAP protocol Finite State Machine, is valid. This function accepts,
196 * as a parameter, the list of message types that are allowed in a certain
197 * situation, and it returns the one that occurs.
198 *
199 * \param errbuf: a pointer to a user-allocated buffer (of size
200 * PCAP_ERRBUF_SIZE) that will contain the error message (in case there
201 * is one). It could either be a problem that occurred inside this function
202 * (e.g. a network problem in case it tries to send an error to our peer
203 * and the send() call fails), an error message thathas been sent to us
204 * from the other party, or a version error (the message received has a
205 * version number that is incompatible with ours).
206 *
207 * \param sock: the socket that has to be used to receive data. This
208 * function can read data from socket in case the version contained into
209 * the message is not compatible with ours. In that case, all the message
210 * is purged from the socket, so that the following recv() calls will
211 * return a new message.
212 *
213 * \param header: a pointer to and 'rpcap_header' structure that keeps
214 * the data received from the network (still in network byte order) and
215 * that has to be checked.
216 *
217 * \param first: this function has a variable number of parameters. From
218 * this point on, all the messages that are valid in this context must be
219 * passed as parameters. The message type list must be terminated with a
220 * '0' value, the null message type, which means 'no more types to check'.
221 * The RPCAP protocol does not define anything with message type equal to
222 * zero, so there is no ambiguity in using this value as a list terminator.
223 *
224 * \return The message type of the message that has been detected. In case
225 * of errors (e.g. the header contains a type that is not listed among the
226 * allowed types), this function will return the following codes:
227 * - (-1) if the version is incompatible.
228 * - (-2) if the code is not among the one listed into the parameters list
229 * - (-3) if a network error (connection reset, ...)
230 * - RPCAP_MSG_ERROR if the message is an error message (it follows that
231 * the RPCAP_MSG_ERROR could not be present in the allowed message-types
232 * list, because this function checks for errors anyway)
233 *
234 * In case either the version is incompatible or nothing matches (i.e. it
235 * returns '-1' or '-2'), it discards the message body (i.e. it reads the
236 * remaining part of the message from the network and it discards it) so
237 * that the application is ready to receive a new message.
238 */
239 int
240 rpcap_checkmsg(char *errbuf, SOCKET sock, struct rpcap_header *header, uint8 first, ...)
241 {
242 va_list ap;
243 uint8 type;
244 int32 len;
245 char remote_errbuf[PCAP_ERRBUF_SIZE];
246
247 /* Check if the present version of the protocol can handle this message */
248 if (header->ver != RPCAP_VERSION)
249 {
250 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Incompatible version number: message discarded.");
251
252 /*
253 * Discard the rest of the packet.
254 */
255 if (sock_discard(sock, ntohl(header->plen), NULL, 0) == -1) {
256 /*
257 * Network error.
258 */
259 return -3;
260 }
261 return -1;
262 }
263
264 va_start(ap, first);
265
266 type = first;
267
268 while (type != 0)
269 {
270 /*
271 * The message matches with one of the types listed
272 * There is no need of conversions since both values are uint8
273 *
274 * Check if the other side reported an error.
275 * If yes, it retrieves it and it returns it back to the caller
276 */
277 if (header->type == RPCAP_MSG_ERROR)
278 {
279 len = ntohl(header->plen);
280
281 if (len >= PCAP_ERRBUF_SIZE)
282 {
283 if (sock_recv(sock, remote_errbuf, PCAP_ERRBUF_SIZE - 1, SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) == -1)
284 {
285 va_end(ap);
286 return -3;
287 }
288
289 sock_discard(sock, len - (PCAP_ERRBUF_SIZE - 1), NULL, 0);
290
291 /*
292 * Copy the received string to errbuf, and
293 * null-terminate it.
294 */
295 memcpy(errbuf, remote_errbuf, PCAP_ERRBUF_SIZE - 1);
296 errbuf[PCAP_ERRBUF_SIZE - 1] = '\0';
297 }
298 else if (len == 0)
299 {
300 /* Empty error string. */
301 errbuf[0] = '\0';
302 }
303 else
304 {
305 if (sock_recv(sock, remote_errbuf, len, SOCK_RECEIVEALL_YES, errbuf, PCAP_ERRBUF_SIZE) == -1)
306 {
307 va_end(ap);
308 return -3;
309 }
310
311 /*
312 * Copy the received string to errbuf, and
313 * null-terminate it.
314 */
315 memcpy(errbuf, remote_errbuf, len - 1);
316 errbuf[len] = '\0';
317 }
318
319 va_end(ap);
320 return header->type;
321 }
322
323 if (header->type == type)
324 {
325 va_end(ap);
326 return header->type;
327 }
328
329 /* get next argument */
330 type = va_arg(ap, int);
331 }
332
333 /* we already have an error, so please discard this one */
334 sock_discard(sock, ntohl(header->plen), NULL, 0);
335
336 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The other endpoint sent a message that is not allowed here.");
337 SOCK_ASSERT(errbuf, 1);
338
339 va_end(ap);
340 return -2;
341 }