]>
The Tcpdump Group git mirrors - libpcap/blob - rpcap-protocol.c
2 * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy)
3 * Copyright (c) 2005 - 2008 CACE Technologies, Davis (California)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
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.
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>
48 * This file contains functions used both by the rpcap client and the
53 * This function sends a RPCAP error to our peer.
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.
62 * \param sock: the socket we are currently using.
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.
68 * \param errcode: a integer which tells the other party the type of error
69 * we had; currently is is not too much used.
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.
75 * \return '0' if everything is fine, '-1' if some errors occurred. The
76 * error message is returned in the 'errbuf' variable.
79 rpcap_senderror(SOCKET sock
, char *error
, unsigned short errcode
, char *errbuf
)
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 */
85 length
= (uint16
)strlen(error
);
87 if (length
> PCAP_ERRBUF_SIZE
)
88 length
= PCAP_ERRBUF_SIZE
;
90 rpcap_createhdr((struct rpcap_header
*) sendbuf
, RPCAP_MSG_ERROR
, errcode
, length
);
92 if (sock_bufferize(NULL
, sizeof(struct rpcap_header
), NULL
, &sendbufidx
,
93 RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
))
96 if (sock_bufferize(error
, length
, sendbuf
, &sendbufidx
,
97 RPCAP_NETBUF_SIZE
, SOCKBUF_BUFFERIZE
, errbuf
, PCAP_ERRBUF_SIZE
))
100 if (sock_send(sock
, sendbuf
, sendbufidx
, errbuf
, PCAP_ERRBUF_SIZE
))
107 * This function fills in a structure of type rpcap_header.
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.
113 * \param header: a pointer to a user-allocated buffer which will contain
114 * the serialized header, ready to be sent on the network.
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.
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.
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.
125 * \return Nothing. The serialized header is returned into the 'header'
129 rpcap_createhdr(struct rpcap_header
*header
, uint8 type
, uint16 value
, uint32 length
)
131 memset(header
, 0, sizeof(struct rpcap_header
));
133 header
->ver
= RPCAP_VERSION
;
135 header
->value
= htons(value
);
136 header
->plen
= htonl(length
);
140 * Convert a message type to a string containing the type name.
142 static const char *requests
[] =
144 NULL
, /* not a valid message type */
146 "RPCAP_MSG_FINDALLIF_REQ",
147 "RPCAP_MSG_OPEN_REQ",
148 "RPCAP_MSG_STARTCAP_REQ",
149 "RPCAP_MSG_UPDATEFILTER_REQ",
152 "RPCAP_MSG_AUTH_REQ",
153 "RPCAP_MSG_STATS_REQ",
154 "RPCAP_MSG_ENDCAP_REQ",
155 "RPCAP_MSG_SETSAMPLING_REQ",
157 #define NUM_REQ_TYPES (sizeof requests / sizeof requests[0])
159 static const char *replies
[] =
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",
174 #define NUM_REPLY_TYPES (sizeof replies / sizeof replies[0])
177 rpcap_msg_type_string(uint8 type
)
179 if (type
& RPCAP_MSG_IS_REPLY
) {
180 type
&= ~RPCAP_MSG_IS_REPLY
;
181 if (type
>= NUM_REPLY_TYPES
)
183 return replies
[type
];
185 if (type
> NUM_REQ_TYPES
)
187 return requests
[type
];
192 * This function checks whether the header of the received message is correct.
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.
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).
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.
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.
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.
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)
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.
240 rpcap_checkmsg(char *errbuf
, SOCKET sock
, struct rpcap_header
*header
, uint8 first
, ...)
245 char remote_errbuf
[PCAP_ERRBUF_SIZE
];
247 /* Check if the present version of the protocol can handle this message */
248 if (header
->ver
!= RPCAP_VERSION
)
250 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Incompatible version number: message discarded.");
253 * Discard the rest of the packet.
255 if (sock_discard(sock
, ntohl(header
->plen
), NULL
, 0) == -1) {
271 * The message matches with one of the types listed
272 * There is no need of conversions since both values are uint8
274 * Check if the other side reported an error.
275 * If yes, it retrieves it and it returns it back to the caller
277 if (header
->type
== RPCAP_MSG_ERROR
)
279 len
= ntohl(header
->plen
);
281 if (len
>= PCAP_ERRBUF_SIZE
)
283 if (sock_recv(sock
, remote_errbuf
, PCAP_ERRBUF_SIZE
- 1, SOCK_RECEIVEALL_YES
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
289 sock_discard(sock
, len
- (PCAP_ERRBUF_SIZE
- 1), NULL
, 0);
292 * Copy the received string to errbuf, and
295 memcpy(errbuf
, remote_errbuf
, PCAP_ERRBUF_SIZE
- 1);
296 errbuf
[PCAP_ERRBUF_SIZE
- 1] = '\0';
300 /* Empty error string. */
305 if (sock_recv(sock
, remote_errbuf
, len
, SOCK_RECEIVEALL_YES
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
312 * Copy the received string to errbuf, and
315 memcpy(errbuf
, remote_errbuf
, len
- 1);
323 if (header
->type
== type
)
329 /* get next argument */
330 type
= va_arg(ap
, int);
333 /* we already have an error, so please discard this one */
334 sock_discard(sock
, ntohl(header
->plen
), NULL
, 0);
336 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "The other endpoint sent a message that is not allowed here.");
337 SOCK_ASSERT(errbuf
, 1);