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