]>
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 checks whether the version contained into the message is
54 * compatible with the one handled by this implementation.
56 * Right now, this function does not have any sophisticated task: if the
57 * versions are different, it returns -1 and it discards the message.
58 * If new versions of the protocol are created, there will need to be
59 * a negotiation phase early in the process of connecting to our peer,
60 * so that the highest version supported by both sides can be used.
62 * \param sock: the socket that has to be used to receive data. This
63 * function can read data from socket in case the version contained into
64 * the message is not compatible with ours. In that case, all the message
65 * is purged from the socket, so that the following recv() calls will
66 * return a new (clean) message.
68 * \param header: a pointer to and 'rpcap_header' structure that keeps
69 * the data received from the network (still in network byte order) and
70 * that has to be checked.
72 * \param errbuf: a pointer to a user-allocated buffer (of size
73 * PCAP_ERRBUF_SIZE) that will contain the error message (in case there
74 * is one). The error message is "incompatible version".
76 * \return '0' if everything is fine, '-1' if some errors occurred. The
77 * error message is returned in the 'errbuf' variable.
80 rpcap_checkver(SOCKET sock
, struct rpcap_header
*header
, char *errbuf
)
83 * This is a sample function.
85 * In the real world, you have to check the type code,
86 * and decide accordingly.
88 if (header
->ver
!= RPCAP_VERSION
)
90 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Incompatible version number: message discarded.");
92 /* we already have an error, so please discard this one */
93 sock_discard(sock
, ntohl(header
->plen
), NULL
, 0);
101 * This function sends a RPCAP error to our peer.
103 * It has to be called when the main program detects an error.
104 * It will send to our peer the 'buffer' specified by the user.
105 * This function *does not* request a RPCAP CLOSE connection. A CLOSE
106 * command must be sent explicitly by the program, since we do not know
107 * whether the error can be recovered in some way or if it is a
108 * non-recoverable one.
110 * \param sock: the socket we are currently using.
112 * \param error: an user-allocated (and '0' terminated) buffer that contains
113 * the error description that has to be transmitted to our peer. The
114 * error message cannot be longer than PCAP_ERRBUF_SIZE.
116 * \param errcode: a integer which tells the other party the type of error
117 * we had; currently is is not too much used.
119 * \param errbuf: a pointer to a user-allocated buffer (of size
120 * PCAP_ERRBUF_SIZE) that will contain the error message (in case there
121 * is one). It could be network problem.
123 * \return '0' if everything is fine, '-1' if some errors occurred. The
124 * error message is returned in the 'errbuf' variable.
127 rpcap_senderror(SOCKET sock
, char *error
, unsigned short errcode
, char *errbuf
)
129 char sendbuf
[RPCAP_NETBUF_SIZE
]; /* temporary buffer in which data to be sent is buffered */
130 int sendbufidx
= 0; /* index which keeps the number of bytes currently buffered */
133 length
= (uint16
)strlen(error
);
135 if (length
> PCAP_ERRBUF_SIZE
)
136 length
= PCAP_ERRBUF_SIZE
;
138 rpcap_createhdr((struct rpcap_header
*) sendbuf
, RPCAP_MSG_ERROR
, errcode
, length
);
140 if (sock_bufferize(NULL
, sizeof(struct rpcap_header
), NULL
, &sendbufidx
,
141 RPCAP_NETBUF_SIZE
, SOCKBUF_CHECKONLY
, errbuf
, PCAP_ERRBUF_SIZE
))
144 if (sock_bufferize(error
, length
, sendbuf
, &sendbufidx
,
145 RPCAP_NETBUF_SIZE
, SOCKBUF_BUFFERIZE
, errbuf
, PCAP_ERRBUF_SIZE
))
148 if (sock_send(sock
, sendbuf
, sendbufidx
, errbuf
, PCAP_ERRBUF_SIZE
))
155 * This function fills in a structure of type rpcap_header.
157 * It is provided just because the creation of an rpcap header is a common
158 * task. It accepts all the values that appears into an rpcap_header, and
159 * it puts them in place using the proper hton() calls.
161 * \param header: a pointer to a user-allocated buffer which will contain
162 * the serialized header, ready to be sent on the network.
164 * \param type: a value (in the host by order) which will be placed into the
165 * header.type field and that represents the type of the current message.
167 * \param value: a value (in the host by order) which will be placed into
168 * the header.value field and that has a message-dependent meaning.
170 * \param length: a value (in the host by order) which will be placed into
171 * the header.length field, representing the payload length of the message.
173 * \return Nothing. The serialized header is returned into the 'header'
177 rpcap_createhdr(struct rpcap_header
*header
, uint8 type
, uint16 value
, uint32 length
)
179 memset(header
, 0, sizeof(struct rpcap_header
));
181 header
->ver
= RPCAP_VERSION
;
183 header
->value
= htons(value
);
184 header
->plen
= htonl(length
);
188 * This function checks whether the header of the received message is correct.
190 * It is a way to easily check if the message received, in a certain state
191 * of the RPCAP protocol Finite State Machine, is valid. This function accepts,
192 * as a parameter, the list of message types that are allowed in a certain
193 * situation, and it returns the one that occurs.
195 * \param errbuf: a pointer to a user-allocated buffer (of size
196 * PCAP_ERRBUF_SIZE) that will contain the error message (in case there
197 * is one). It could either be a problem that occurred inside this function
198 * (e.g. a network problem in case it tries to send an error to our peer
199 * and the send() call fails), an error message thathas been sent to us
200 * from the other party, or a version error (the message received has a
201 * version number that is incompatible with ours).
203 * \param sock: the socket that has to be used to receive data. This
204 * function can read data from socket in case the version contained into
205 * the message is not compatible with ours. In that case, all the message
206 * is purged from the socket, so that the following recv() calls will
207 * return a new message.
209 * \param header: a pointer to and 'rpcap_header' structure that keeps
210 * the data received from the network (still in network byte order) and
211 * that has to be checked.
213 * \param first: this function has a variable number of parameters. From
214 * this point on, all the messages that are valid in this context must be
215 * passed as parameters. The message type list must be terminated with a
216 * '0' value, the null message type, which means 'no more types to check'.
217 * The RPCAP protocol does not define anything with message type equal to
218 * zero, so there is no ambiguity in using this value as a list terminator.
220 * \return The message type of the message that has been detected. In case
221 * of errors (e.g. the header contains a type that is not listed among the
222 * allowed types), this function will return the following codes:
223 * - (-1) if the version is incompatible.
224 * - (-2) if the code is not among the one listed into the parameters list
225 * - (-3) if a network error (connection reset, ...)
226 * - RPCAP_MSG_ERROR if the message is an error message (it follows that
227 * the RPCAP_MSG_ERROR could not be present in the allowed message-types
228 * list, because this function checks for errors anyway)
230 * In case either the version is incompatible or nothing matches (i.e. it
231 * returns '-1' or '-2'), it discards the message body (i.e. it reads the
232 * remaining part of the message from the network and it discards it) so
233 * that the application is ready to receive a new message.
236 rpcap_checkmsg(char *errbuf
, SOCKET sock
, struct rpcap_header
*header
, uint8 first
, ...)
244 /* Check if the present version of the protocol can handle this message */
245 if (rpcap_checkver(sock
, header
, errbuf
))
247 SOCK_ASSERT(errbuf
, 1);
258 * The message matches with one of the types listed
259 * There is no need of conversions since both values are uint8
261 * Check if the other side reported an error.
262 * If yes, it retrieves it and it returns it back to the caller
264 if (header
->type
== RPCAP_MSG_ERROR
)
266 len
= ntohl(header
->plen
);
268 if (len
>= PCAP_ERRBUF_SIZE
)
270 if (sock_recv(sock
, errbuf
, PCAP_ERRBUF_SIZE
- 1, SOCK_RECEIVEALL_YES
, errbuf
, PCAP_ERRBUF_SIZE
))
273 sock_discard(sock
, len
- (PCAP_ERRBUF_SIZE
- 1), NULL
, 0);
275 /* Put '\0' at the end of the string */
276 errbuf
[PCAP_ERRBUF_SIZE
- 1] = 0;
280 if (sock_recv(sock
, errbuf
, len
, SOCK_RECEIVEALL_YES
, errbuf
, PCAP_ERRBUF_SIZE
) == -1)
283 /* Put '\0' at the end of the string */
291 if (header
->type
== type
)
297 /* get next argument */
298 type
= va_arg(ap
, int);
301 /* we already have an error, so please discard this one */
302 sock_discard(sock
, ntohl(header
->plen
), NULL
, 0);
304 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "The other endpoint sent a message that is not allowed here.");
305 SOCK_ASSERT(errbuf
, 1);