]> The Tcpdump Group git mirrors - libpcap/blob - pcap-new.c
Move rpcap-protocol.h to the top-level directory.
[libpcap] / pcap-new.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 "pcap-int.h" // for the details of the pcap_t structure
39 #include "sockutils.h"
40 #include "rpcap-protocol.h"
41 #include "pcap-rpcap-int.h"
42 #include <errno.h> // for the errno variable
43 #include <stdlib.h> // for malloc(), free(), ...
44 #include <string.h> // for strstr, etc
45
46 #ifndef _WIN32
47 #include <dirent.h> // for readdir
48 #endif
49
50 /* Keeps a list of all the opened connections in the active mode. */
51 extern struct activehosts *activeHosts;
52
53 /*
54 * \brief Keeps the main socket identifier when we want to accept a new remote connection (active mode only).
55 * See the documentation of pcap_remoteact_accept() and pcap_remoteact_cleanup() for more details.
56 */
57 SOCKET sockmain;
58
59 /* String identifier to be used in the pcap_findalldevs_ex() */
60 #define PCAP_TEXT_SOURCE_FILE "File"
61 /* String identifier to be used in the pcap_findalldevs_ex() */
62 #define PCAP_TEXT_SOURCE_ADAPTER "Network adapter"
63
64 /* String identifier to be used in the pcap_findalldevs_ex() */
65 #define PCAP_TEXT_SOURCE_ON_LOCAL_HOST "on local host"
66
67 /****************************************************
68 * *
69 * Function bodies *
70 * *
71 ****************************************************/
72
73 int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf)
74 {
75 int type;
76 char name[PCAP_BUF_SIZE], path[PCAP_BUF_SIZE], filename[PCAP_BUF_SIZE];
77 pcap_t *fp;
78 char tmpstring[PCAP_BUF_SIZE + 1]; /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */
79 pcap_if_t *dev; /* Previous device into the pcap_if_t chain */
80
81 (*alldevs) = NULL;
82
83 if (strlen(source) > PCAP_BUF_SIZE)
84 {
85 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
86 return -1;
87 }
88
89 /*
90 * Determine the type of the source (file, local, remote)
91 * There are some differences if pcap_findalldevs_ex() is called to list files and remote adapters.
92 * In the first case, the name of the directory we have to look into must be present (therefore
93 * the 'name' parameter of the pcap_parsesrcstr() is present).
94 * In the second case, the name of the adapter is not required (we need just the host). So, we have
95 * to use a first time this function to get the source type, and a second time to get the appropriate
96 * info, which depends on the source type.
97 */
98 if (pcap_parsesrcstr(source, &type, NULL, NULL, NULL, errbuf) == -1)
99 return -1;
100
101 switch (type)
102 {
103 case PCAP_SRC_IFLOCAL:
104 if (pcap_parsesrcstr(source, &type, NULL, NULL, NULL, errbuf) == -1)
105 return -1;
106
107 /* Initialize temporary string */
108 tmpstring[PCAP_BUF_SIZE] = 0;
109
110 /* The user wants to retrieve adapters from a local host */
111 if (pcap_findalldevs(alldevs, errbuf) == -1)
112 return -1;
113
114 if ((alldevs == NULL) || (*alldevs == NULL))
115 {
116 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
117 "No interfaces found! Make sure libpcap/WinPcap is properly installed"
118 " on the local machine.");
119 return -1;
120 }
121
122 /* Scan all the interfaces and modify name and description */
123 /* This is a trick in order to avoid the re-implementation of the pcap_findalldevs here */
124 dev = *alldevs;
125 while (dev)
126 {
127 /* Create the new device identifier */
128 if (pcap_createsrcstr(tmpstring, PCAP_SRC_IFLOCAL, NULL, NULL, dev->name, errbuf) == -1)
129 return -1;
130
131 /* Delete the old pointer */
132 free(dev->name);
133
134 /* Make a copy of the new device identifier */
135 dev->name = strdup(tmpstring);
136 if (dev->name == NULL)
137 {
138 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
139 return -1;
140 }
141
142 /* Create the new device description */
143 if ((dev->description == NULL) || (dev->description[0] == 0))
144 pcap_snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_ADAPTER,
145 dev->name, PCAP_TEXT_SOURCE_ON_LOCAL_HOST);
146 else
147 pcap_snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_ADAPTER,
148 dev->description, PCAP_TEXT_SOURCE_ON_LOCAL_HOST);
149
150 /* Delete the old pointer */
151 free(dev->description);
152
153 /* Make a copy of the description */
154 dev->description = strdup(tmpstring);
155 if (dev->description == NULL)
156 {
157 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
158 return -1;
159 }
160
161 dev = dev->next;
162 }
163
164 return 0;
165
166 case PCAP_SRC_FILE:
167 {
168 size_t stringlen;
169 #ifdef _WIN32
170 WIN32_FIND_DATA filedata;
171 HANDLE filehandle;
172 #else
173 struct dirent *filedata;
174 DIR *unixdir;
175 #endif
176
177 if (pcap_parsesrcstr(source, &type, NULL, NULL, name, errbuf) == -1)
178 return -1;
179
180 /* Check that the filename is correct */
181 stringlen = strlen(name);
182
183 /* The directory must end with '\' in Win32 and '/' in UNIX */
184 #ifdef _WIN32
185 #define ENDING_CHAR '\\'
186 #else
187 #define ENDING_CHAR '/'
188 #endif
189
190 if (name[stringlen - 1] != ENDING_CHAR)
191 {
192 name[stringlen] = ENDING_CHAR;
193 name[stringlen + 1] = 0;
194
195 stringlen++;
196 }
197
198 /* Save the path for future reference */
199 pcap_snprintf(path, sizeof(path), "%s", name);
200
201 #ifdef _WIN32
202 /* To perform directory listing, Win32 must have an 'asterisk' as ending char */
203 if (name[stringlen - 1] != '*')
204 {
205 name[stringlen] = '*';
206 name[stringlen + 1] = 0;
207 }
208
209 filehandle = FindFirstFile(name, &filedata);
210
211 if (filehandle == INVALID_HANDLE_VALUE)
212 {
213 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
214 return -1;
215 }
216
217 #else
218 /* opening the folder */
219 unixdir= opendir(path);
220
221 /* get the first file into it */
222 filedata= readdir(unixdir);
223
224 if (filedata == NULL)
225 {
226 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
227 return -1;
228 }
229 #endif
230
231 do
232 {
233
234 #ifdef _WIN32
235 pcap_snprintf(filename, sizeof(filename), "%s%s", path, filedata.cFileName);
236 #else
237 pcap_snprintf(filename, sizeof(filename), "%s%s", path, filedata->d_name);
238 #endif
239
240 fp = pcap_open_offline(filename, errbuf);
241
242 if (fp)
243 {
244 /* allocate the main structure */
245 if (*alldevs == NULL) /* This is in case it is the first file */
246 {
247 (*alldevs) = (pcap_if_t *)malloc(sizeof(pcap_if_t));
248 dev = (*alldevs);
249 }
250 else
251 {
252 dev->next = (pcap_if_t *)malloc(sizeof(pcap_if_t));
253 dev = dev->next;
254 }
255
256 /* check that the malloc() didn't fail */
257 if (dev == NULL)
258 {
259 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
260 return -1;
261 }
262
263 /* Initialize the structure to 'zero' */
264 memset(dev, 0, sizeof(pcap_if_t));
265
266 /* Create the new source identifier */
267 if (pcap_createsrcstr(tmpstring, PCAP_SRC_FILE, NULL, NULL, filename, errbuf) == -1)
268 return -1;
269
270 stringlen = strlen(tmpstring);
271
272 dev->name = (char *)malloc(stringlen + 1);
273 if (dev->name == NULL)
274 {
275 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
276 return -1;
277 }
278
279 strlcpy(dev->name, tmpstring, stringlen);
280
281 dev->name[stringlen] = 0;
282
283 /* Create the description */
284 pcap_snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_FILE,
285 filename, PCAP_TEXT_SOURCE_ON_LOCAL_HOST);
286
287 stringlen = strlen(tmpstring);
288
289 dev->description = (char *)malloc(stringlen + 1);
290
291 if (dev->description == NULL)
292 {
293 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
294 return -1;
295 }
296
297 /* Copy the new device description into the correct memory location */
298 strlcpy(dev->description, tmpstring, stringlen + 1);
299
300 pcap_close(fp);
301 }
302 }
303 #ifdef _WIN32
304 while (FindNextFile(filehandle, &filedata) != 0);
305 #else
306 while ( (filedata= readdir(unixdir)) != NULL);
307 #endif
308
309
310 #ifdef _WIN32
311 /* Close the search handle. */
312 FindClose(filehandle);
313 #endif
314
315 return 0;
316 }
317
318 case PCAP_SRC_IFREMOTE:
319 return pcap_findalldevs_ex_remote(source, auth, alldevs, errbuf);
320
321 default:
322 strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE);
323 return -1;
324 }
325 }
326
327 int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf)
328 {
329 switch (type)
330 {
331 case PCAP_SRC_FILE:
332 {
333 strlcpy(source, PCAP_SRC_FILE_STRING, PCAP_BUF_SIZE);
334 if ((name) && (*name))
335 {
336 strlcat(source, name, PCAP_BUF_SIZE);
337 return 0;
338 }
339 else
340 {
341 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The file name cannot be NULL.");
342 return -1;
343 }
344 }
345
346 case PCAP_SRC_IFREMOTE:
347 {
348 strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE);
349 if ((host) && (*host))
350 {
351 if ((strcspn(host, "aAbBcCdDeEfFgGhHjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ")) == strlen(host))
352 {
353 /* the host name does not contains alphabetic chars. So, it is a numeric address */
354 /* In this case we have to include it between square brackets */
355 strlcat(source, "[", PCAP_BUF_SIZE);
356 strlcat(source, host, PCAP_BUF_SIZE);
357 strlcat(source, "]", PCAP_BUF_SIZE);
358 }
359 else
360 strlcat(source, host, PCAP_BUF_SIZE);
361
362 if ((port) && (*port))
363 {
364 strlcat(source, ":", PCAP_BUF_SIZE);
365 strlcat(source, port, PCAP_BUF_SIZE);
366 }
367
368 strlcat(source, "/", PCAP_BUF_SIZE);
369 }
370 else
371 {
372 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The host name cannot be NULL.");
373 return -1;
374 }
375
376 if ((name) && (*name))
377 strlcat(source, name, PCAP_BUF_SIZE);
378
379 return 0;
380 }
381
382 case PCAP_SRC_IFLOCAL:
383 {
384 strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE);
385
386 if ((name) && (*name))
387 strlcat(source, name, PCAP_BUF_SIZE);
388
389 return 0;
390 }
391
392 default:
393 {
394 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The interface type is not valid.");
395 return -1;
396 }
397 }
398 }
399
400 int pcap_parsesrcstr(const char *source, int *type, char *host, char *port, char *name, char *errbuf)
401 {
402 char *ptr;
403 int ntoken;
404 char tmpname[PCAP_BUF_SIZE];
405 char tmphost[PCAP_BUF_SIZE];
406 char tmpport[PCAP_BUF_SIZE];
407 int tmptype;
408
409 /* Initialization stuff */
410 tmpname[0] = 0;
411 tmphost[0] = 0;
412 tmpport[0] = 0;
413
414 if (host)
415 *host = 0;
416 if (port)
417 *port = 0;
418 if (name)
419 *name = 0;
420
421 /* Look for a 'rpcap://' identifier */
422 if ((ptr = strstr(source, PCAP_SRC_IF_STRING)) != NULL)
423 {
424 if (strlen(PCAP_SRC_IF_STRING) == strlen(source))
425 {
426 /* The source identifier contains only the 'rpcap://' string. */
427 /* So, this is a local capture. */
428 *type = PCAP_SRC_IFLOCAL;
429 return 0;
430 }
431
432 ptr += strlen(PCAP_SRC_IF_STRING);
433
434 if (strchr(ptr, '[')) /* This is probably a numeric address */
435 {
436 ntoken = sscanf(ptr, "[%[1234567890:.]]:%[^/]/%s", tmphost, tmpport, tmpname);
437
438 if (ntoken == 1) /* probably the port is missing */
439 ntoken = sscanf(ptr, "[%[1234567890:.]]/%s", tmphost, tmpname);
440
441 tmptype = PCAP_SRC_IFREMOTE;
442 }
443 else
444 {
445 ntoken = sscanf(ptr, "%[^/:]:%[^/]/%s", tmphost, tmpport, tmpname);
446
447 if (ntoken == 1)
448 {
449 /*
450 * This can be due to two reasons:
451 * - we want a remote capture, but the network port is missing
452 * - we want to do a local capture
453 * To distinguish between the two, we look for the '/' char
454 */
455 if (strchr(ptr, '/'))
456 {
457 /* We're on a remote capture */
458 sscanf(ptr, "%[^/]/%s", tmphost, tmpname);
459 tmptype = PCAP_SRC_IFREMOTE;
460 }
461 else
462 {
463 /* We're on a local capture */
464 if (*ptr)
465 strlcpy(tmpname, ptr, PCAP_BUF_SIZE);
466
467 /* Clean the host name, since it is a remote capture */
468 /* NOTE: the host name has been assigned in the previous "ntoken= sscanf(...)" line */
469 tmphost[0] = 0;
470
471 tmptype = PCAP_SRC_IFLOCAL;
472 }
473 }
474 else
475 tmptype = PCAP_SRC_IFREMOTE;
476 }
477
478 if (host)
479 strlcpy(host, tmphost, PCAP_BUF_SIZE);
480 if (port)
481 strlcpy(port, tmpport, PCAP_BUF_SIZE);
482 if (type)
483 *type = tmptype;
484
485 if (name)
486 {
487 /*
488 * If the user wants the host name, but it cannot be located into the source string, return error
489 * However, if the user is not interested in the interface name (e.g. if we're called by
490 * pcap_findalldevs_ex(), which does not have interface name, do not return error
491 */
492 if (tmpname[0])
493 {
494 strlcpy(name, tmpname, PCAP_BUF_SIZE);
495 }
496 else
497 {
498 if (errbuf)
499 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The interface name has not been specified in the source string.");
500
501 return -1;
502 }
503 }
504
505 return 0;
506 }
507
508 /* Look for a 'file://' identifier */
509 if ((ptr = strstr(source, PCAP_SRC_FILE_STRING)) != NULL)
510 {
511 ptr += strlen(PCAP_SRC_FILE_STRING);
512 if (*ptr)
513 {
514 if (name)
515 strlcpy(name, ptr, PCAP_BUF_SIZE);
516
517 if (type)
518 *type = PCAP_SRC_FILE;
519
520 return 0;
521 }
522 else
523 {
524 if (errbuf)
525 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The file name has not been specified in the source string.");
526
527 return -1;
528 }
529
530 }
531
532 /* Backward compatibility; the user didn't use the 'rpcap://, file://' specifiers */
533 if ((source) && (*source))
534 {
535 if (name)
536 strlcpy(name, source, PCAP_BUF_SIZE);
537
538 if (type)
539 *type = PCAP_SRC_IFLOCAL;
540
541 return 0;
542 }
543 else
544 {
545 if (errbuf)
546 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The interface name has not been specified in the source string.");
547
548 return -1;
549 }
550 };
551
552 pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf)
553 {
554 char name[PCAP_BUF_SIZE];
555 int type;
556 pcap_t *fp;
557 int status;
558
559 if (strlen(source) > PCAP_BUF_SIZE)
560 {
561 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
562 return NULL;
563 }
564
565 /*
566 * Determine the type of the source (file, local, remote) and,
567 * if it's file or local, the name of the file or capture device.
568 */
569 if (pcap_parsesrcstr(source, &type, NULL, NULL, name, errbuf) == -1)
570 return NULL;
571
572 switch (type)
573 {
574 case PCAP_SRC_FILE:
575 fp = pcap_open_offline(name, errbuf);
576 break;
577
578 case PCAP_SRC_IFLOCAL:
579 fp = pcap_create(source, errbuf);
580 if (fp == NULL)
581 return (NULL);
582 status = pcap_set_snaplen(fp, snaplen);
583 if (status < 0)
584 goto fail;
585 if (flags & PCAP_OPENFLAG_PROMISCUOUS)
586 {
587 status = pcap_set_promisc(fp, 1);
588 if (status < 0)
589 goto fail;
590 }
591 if (flags & PCAP_OPENFLAG_MAX_RESPONSIVENESS)
592 {
593 status = pcap_set_immediate_mode(fp, 1);
594 if (status < 0)
595 goto fail;
596 }
597 status = pcap_set_timeout(fp, read_timeout);
598 if (status < 0)
599 goto fail;
600 status = pcap_activate(fp);
601 if (status < 0)
602 goto fail;
603 #ifdef _WIN32
604 /*
605 * This flag is supported on Windows only.
606 * XXX - is there a way to support it with
607 * the capture mechanisms on UN*X? It's not
608 * exactly a "set direction" operation; I
609 * think it means "do not capture packets
610 * injected with pcap_sendpacket() or
611 * pcap_inject()".
612 */
613 if (fp->adapter != NULL)
614 {
615 /* disable loopback capture if requested */
616 if (flags & PCAP_OPENFLAG_NOCAPTURE_LOCAL)
617 {
618 if (!PacketSetLoopbackBehavior(fp->adapter, NPF_DISABLE_LOOPBACK))
619 {
620 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Unable to disable the capture of loopback packets.");
621 pcap_close(fp);
622 return NULL;
623 }
624 }
625 }
626 #endif /* _WIN32 */
627 break;
628
629 fail:
630 if (status == PCAP_ERROR)
631 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
632 source, fp->errbuf);
633 else if (status == PCAP_ERROR_NO_SUCH_DEVICE ||
634 status == PCAP_ERROR_PERM_DENIED ||
635 status == PCAP_ERROR_PROMISC_PERM_DENIED)
636 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)",
637 source, pcap_statustostr(status), fp->errbuf);
638 else
639 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
640 source, pcap_statustostr(status));
641 pcap_close(fp);
642 return NULL;
643
644 case PCAP_SRC_IFREMOTE:
645 /*
646 * Although we already have host, port and iface, we prefer
647 * to pass only 'source' to pcap_open_rpcap(), so that it
648 * has to call pcap_parsesrcstr() again.
649 * This is less optimized, but much clearer.
650 */
651 fp = pcap_open_rpcap(source, snaplen, flags, read_timeout, auth, errbuf);
652 break;
653
654 default:
655 strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE);
656 return NULL;
657 }
658 return fp;
659 }
660
661 struct pcap_samp *pcap_setsampling(pcap_t *p)
662 {
663 return &p->rmt_samp;
664 }
665
666 SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf)
667 {
668 /* socket-related variables */
669 struct addrinfo hints; /* temporary struct to keep settings needed to open the new socket */
670 struct addrinfo *addrinfo; /* keeps the addrinfo chain; required to open a new socket */
671 struct sockaddr_storage from; /* generic sockaddr_storage variable */
672 socklen_t fromlen; /* keeps the length of the sockaddr_storage variable */
673 SOCKET sockctrl; /* keeps the main socket identifier */
674 struct activehosts *temp, *prev; /* temp var needed to scan he host list chain */
675
676 *connectinghost = 0; /* just in case */
677
678 /* Prepare to open a new server socket */
679 memset(&hints, 0, sizeof(struct addrinfo));
680 /* WARNING Currently it supports only ONE socket family among ipv4 and IPv6 */
681 hints.ai_family = AF_INET; /* PF_UNSPEC to have both IPv4 and IPv6 server */
682 hints.ai_flags = AI_PASSIVE; /* Ready to a bind() socket */
683 hints.ai_socktype = SOCK_STREAM;
684
685 /* Warning: this call can be the first one called by the user. */
686 /* For this reason, we have to initialize the WinSock support. */
687 if (sock_init(errbuf, PCAP_ERRBUF_SIZE) == -1)
688 return -1;
689
690 /* Do the work */
691 if ((port == NULL) || (port[0] == 0))
692 {
693 if (sock_initaddress(address, RPCAP_DEFAULT_NETPORT_ACTIVE, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
694 {
695 SOCK_ASSERT(errbuf, 1);
696 return -2;
697 }
698 }
699 else
700 {
701 if (sock_initaddress(address, port, &hints, &addrinfo, errbuf, PCAP_ERRBUF_SIZE) == -1)
702 {
703 SOCK_ASSERT(errbuf, 1);
704 return -2;
705 }
706 }
707
708
709 if ((sockmain = sock_open(addrinfo, SOCKOPEN_SERVER, 1, errbuf, PCAP_ERRBUF_SIZE)) == -1)
710 {
711 SOCK_ASSERT(errbuf, 1);
712 return -2;
713 }
714
715 /* Connection creation */
716 fromlen = sizeof(struct sockaddr_storage);
717
718 sockctrl = accept(sockmain, (struct sockaddr *) &from, &fromlen);
719
720 /* We're not using sock_close, since we do not want to send a shutdown */
721 /* (which is not allowed on a non-connected socket) */
722 closesocket(sockmain);
723 sockmain = 0;
724
725 if (sockctrl == -1)
726 {
727 sock_geterror("accept(): ", errbuf, PCAP_ERRBUF_SIZE);
728 return -2;
729 }
730
731 /* Get the numeric for of the name of the connecting host */
732 if (getnameinfo((struct sockaddr *) &from, fromlen, connectinghost, RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST))
733 {
734 sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE);
735 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, NULL);
736 sock_close(sockctrl, NULL, 0);
737 return -1;
738 }
739
740 /* checks if the connecting host is among the ones allowed */
741 if (sock_check_hostlist((char *)hostlist, RPCAP_HOSTLIST_SEP, &from, errbuf, PCAP_ERRBUF_SIZE) < 0)
742 {
743 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, NULL);
744 sock_close(sockctrl, NULL, 0);
745 return -1;
746 }
747
748 /* Send authentication to the remote machine */
749 if (rpcap_sendauth(sockctrl, auth, errbuf) == -1)
750 {
751 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, NULL);
752 sock_close(sockctrl, NULL, 0);
753 return -3;
754 }
755
756 /* Checks that this host does not already have a cntrl connection in place */
757
758 /* Initialize pointers */
759 temp = activeHosts;
760 prev = NULL;
761
762 while (temp)
763 {
764 /* This host already has an active connection in place, so I don't have to update the host list */
765 if (sock_cmpaddr(&temp->host, &from) == 0)
766 return sockctrl;
767
768 prev = temp;
769 temp = temp->next;
770 }
771
772 /* The host does not exist in the list; so I have to update the list */
773 if (prev)
774 {
775 prev->next = (struct activehosts *) malloc(sizeof(struct activehosts));
776 temp = prev->next;
777 }
778 else
779 {
780 activeHosts = (struct activehosts *) malloc(sizeof(struct activehosts));
781 temp = activeHosts;
782 }
783
784 if (temp == NULL)
785 {
786 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
787 rpcap_senderror(sockctrl, errbuf, PCAP_ERR_REMOTEACCEPT, NULL);
788 sock_close(sockctrl, NULL, 0);
789 return -1;
790 }
791
792 memcpy(&temp->host, &from, fromlen);
793 temp->sockctrl = sockctrl;
794 temp->next = NULL;
795
796 return sockctrl;
797 }
798
799 int pcap_remoteact_close(const char *host, char *errbuf)
800 {
801 struct activehosts *temp, *prev; /* temp var needed to scan the host list chain */
802 struct addrinfo hints, *addrinfo, *ai_next; /* temp var needed to translate between hostname to its address */
803 int retval;
804
805 temp = activeHosts;
806 prev = NULL;
807
808 /* retrieve the network address corresponding to 'host' */
809 addrinfo = NULL;
810 memset(&hints, 0, sizeof(struct addrinfo));
811 hints.ai_family = PF_UNSPEC;
812 hints.ai_socktype = SOCK_STREAM;
813
814 retval = getaddrinfo(host, "0", &hints, &addrinfo);
815 if (retval != 0)
816 {
817 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "getaddrinfo() %s", gai_strerror(retval));
818 return -1;
819 }
820
821 while (temp)
822 {
823 ai_next = addrinfo;
824 while (ai_next)
825 {
826 if (sock_cmpaddr(&temp->host, (struct sockaddr_storage *) ai_next->ai_addr) == 0)
827 {
828 struct rpcap_header header;
829
830 /* Close this connection */
831 rpcap_createhdr(&header, RPCAP_MSG_CLOSE, 0, 0);
832
833 /* I don't check for errors, since I'm going to close everything */
834 sock_send(temp->sockctrl, (char *)&header, sizeof(struct rpcap_header), errbuf, PCAP_ERRBUF_SIZE);
835
836 if (sock_close(temp->sockctrl, errbuf, PCAP_ERRBUF_SIZE))
837 {
838 /* To avoid inconsistencies in the number of sock_init() */
839 sock_cleanup();
840
841 return -1;
842 }
843
844 if (prev)
845 prev->next = temp->next;
846 else
847 activeHosts = temp->next;
848
849 freeaddrinfo(addrinfo);
850
851 free(temp);
852
853 /* To avoid inconsistencies in the number of sock_init() */
854 sock_cleanup();
855
856 return 0;
857 }
858
859 ai_next = ai_next->ai_next;
860 }
861 prev = temp;
862 temp = temp->next;
863 }
864
865 if (addrinfo)
866 freeaddrinfo(addrinfo);
867
868 /* To avoid inconsistencies in the number of sock_init() */
869 sock_cleanup();
870
871 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The host you want to close the active connection is not known");
872 return -1;
873 }
874
875 void pcap_remoteact_cleanup(void)
876 {
877 /* Very dirty, but it works */
878 if (sockmain)
879 {
880 closesocket(sockmain);
881
882 /* To avoid inconsistencies in the number of sock_init() */
883 sock_cleanup();
884 }
885
886 }
887
888 int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf)
889 {
890 struct activehosts *temp; /* temp var needed to scan the host list chain */
891 size_t len;
892 char hoststr[RPCAP_HOSTLIST_SIZE + 1];
893
894 temp = activeHosts;
895
896 len = 0;
897 *hostlist = 0;
898
899 while (temp)
900 {
901 /*int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, int errbuflen) */
902
903 /* Get the numeric form of the name of the connecting host */
904 if (sock_getascii_addrport((struct sockaddr_storage *) &temp->host, hoststr,
905 RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST, errbuf, PCAP_ERRBUF_SIZE) != -1)
906 /* if (getnameinfo( (struct sockaddr *) &temp->host, sizeof (struct sockaddr_storage), hoststr, */
907 /* RPCAP_HOSTLIST_SIZE, NULL, 0, NI_NUMERICHOST) ) */
908 {
909 /* sock_geterror("getnameinfo(): ", errbuf, PCAP_ERRBUF_SIZE); */
910 return -1;
911 }
912
913 len = len + strlen(hoststr) + 1 /* the separator */;
914
915 if ((size < 0) || (len >= (size_t)size))
916 {
917 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The string you provided is not able to keep "
918 "the hostnames for all the active connections");
919 return -1;
920 }
921
922 strlcat(hostlist, hoststr, PCAP_ERRBUF_SIZE);
923 hostlist[len - 1] = sep;
924 hostlist[len] = 0;
925
926 temp = temp->next;
927 }
928
929 return 0;
930 }