├── Makefile.in ├── README ├── autogen.sh ├── configure.ac └── net2pcap.c /Makefile.in: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env make 2 | 3 | CC= @CC@ 4 | CFLAGS=@CFLAGS@ -O2 -g -Wall -Wp,-D_FORTIFY_SOURCE=2 -fstack-protector-all -fPIE -fPIC 5 | LDFLAGS=@LDFLAGS@ -fPIC -pie -z relro -z now -fstack-protector 6 | LDLIBS=@LIBS@ 7 | prefix := /usr/local 8 | 9 | all: net2pcap 10 | 11 | net2pcap: net2pcap.o 12 | 13 | .PHONY: static 14 | static: net2pcap.$(shell uname -m) 15 | net2pcap.$(shell uname -m): net2pcap.c 16 | $(CC) $(CFLAGS) -static -o $@ $< 17 | 18 | 19 | .PHONY: clean 20 | clean: 21 | rm -f net2pcap.o net2pcap 22 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Net2PCAP is a simple network to pcap capture file for Linux. Its goal 2 | is to be as simple as possible (hence auditable) so that good 3 | confidence can be reached, for it to be used in hostile 4 | environments. 5 | 6 | It does not require any library except a bit of libc. It does not do 7 | anything except dumping network traffic from an interface to a pcap 8 | file. It is less than 600 lines of C. Please audit it ! 9 | 10 | Comparison with tcpdump 11 | 12 | * Yes, tcpdump -w capfile can do almost the same. But the goal of 13 | tcpdump is network debugging (thus, lot of options, packet 14 | disassembly, etc.). The goal of net2pcap is to capture traffic into 15 | a file in hostile environments (honeypots, internet, etc.) for 16 | future analysis. 17 | * net2pcap can run in daemon mode 18 | * net2pcap can reopen its capture file (SIGHUP) (used for capture file rotation) 19 | * net2pcap does not do anything else than reading from network and dumping to file 20 | * net2pcap does not use libpcap 21 | * net2pcap drops its privileges 22 | * net2pcap sandboxes itself (if libseccomp is available) 23 | * net2pcap runs only on Linux 24 | * net2pcap is auditable (less than 600 lines) 25 | 26 | Original code from Philippe Biondi, bugs added by Nicolas Bareil :) 27 | 28 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | autoreconf --install 4 | automake --add-missing --copy > /dev/null 2>&1 5 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([net2pcap], [0.2], [nico@chdir.org], [net2pcap], [http://github.com/nbareil/net2pcap/]) 2 | AC_PREREQ([2.59]) 3 | AC_CONFIG_HEADERS([config.h]) 4 | AC_CONFIG_FILES([Makefile]) 5 | AC_ARG_ENABLE([sandbox], 6 | [ --disable-sandbox do not use SECCOMP sandbox], 7 | [sandbox=${enableval}], [sandbox=auto]) 8 | 9 | have_seccomp=no 10 | 11 | if test "x${sandbox}" != xno; then 12 | AC_SEARCH_LIBS([seccomp_init], [seccomp], [have_seccomp=yes]) 13 | AC_CHECK_HEADERS([seccomp.h]) 14 | fi 15 | 16 | if test "x${sandbox}" = xyes && test "x${have_seccomp}" != xyes; then 17 | AC_MSG_ERROR([ 18 | -------------------------------------------- 19 | Unable to find libseccomp. Abording. 20 | -------------------------------------------- 21 | ]) 22 | fi 23 | 24 | AC_PROG_CC 25 | AC_OUTPUT 26 | -------------------------------------------------------------------------------- /net2pcap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * net2pcap --- an auditable packet capture tool 3 | * see http://www.secdev.org/projects/net2pcap.html 4 | * for more informations 5 | * 6 | * Copyright (C) 2003-2013 Philippe Biondi 7 | * Nicolas Bareil 8 | * 9 | * This program is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public License 11 | * version 2 as published by the Free Software Foundation. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | */ 18 | 19 | #define IDENT "##PACKAGE_NAME -- ## PACKAGE_URL\n" 20 | 21 | #define _FILE_OFFSET_BITS 64 22 | #include "config.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #if HAVE_SECCOMP_H 46 | # include 47 | #endif 48 | #include 49 | #include 50 | #include 51 | 52 | #ifndef O_LARGEFILE /* needed for SECCOMP rule */ 53 | # define O_LARGEFILE 00100000 54 | #endif 55 | 56 | #define MAX(a,b) (a > b ? a : b) 57 | 58 | #define DEFAULT_SNAPLEN 65535 59 | #define MAX_LEN_ERRORMSG 2048 60 | 61 | #if __BYTE_ORDER == __BIG_ENDIAN 62 | # define NATIVE2COMPAT(x) (sizeof(struct timeval) != 8 ? (uint32_t)(x >> 32) : (x)) 63 | #else 64 | # define NATIVE2COMPAT(x) ((uint32_t)(x)) 65 | #endif 66 | 67 | int daemonize = 0; 68 | 69 | #define ERROR(x...) do{LOG(LOG_ERR, "ERROR: " x);exit(EXIT_FAILURE);}while(0) 70 | #define LOG(prio,x...) do{if(daemonize > 1) syslog(prio, x); \ 71 | else fprintf(stderr,"net2pcap: " x);} while(0) 72 | 73 | void PERROR(char *err) { 74 | char errormsg[MAX_LEN_ERRORMSG]; 75 | 76 | strerror_r(errno, errormsg, MAX_LEN_ERRORMSG); 77 | LOG(LOG_CRIT, "%s: %s\n", err, errormsg); 78 | exit(EXIT_FAILURE); 79 | } 80 | 81 | 82 | 83 | #define CRATIONMASK (S_IRUSR|S_IWUSR) 84 | 85 | struct timeval_compat { 86 | uint32_t tv_sec; /* seconds */ 87 | uint32_t tv_usec; /* microseconds */ 88 | }; 89 | 90 | /* From pcap.h */ 91 | 92 | struct pcap_file_header { 93 | uint32_t magic; 94 | uint16_t version_major; 95 | uint16_t version_minor; 96 | int32_t thiszone; /* gmt to local correction */ 97 | uint32_t sigfigs; /* accuracy of timestamps */ 98 | uint32_t snaplen; /* max length saved portion of each pkt */ 99 | uint32_t linktype; /* data link type (LINKTYPE_*) */ 100 | }; 101 | 102 | struct pcap_pkthdr { 103 | struct timeval_compat ts; /* time stamp using 32 bits fields */ 104 | uint32_t caplen; /* length of portion present */ 105 | uint32_t len; /* length this packet (off wire) */ 106 | }; 107 | 108 | 109 | /* mmmh.. what about big endian platforms ? */ 110 | #define PCAP_MAGIC 0xa1b2c3d4 111 | #define PCAP_VERSION_MAJOR 2 112 | #define PCAP_VERSION_MINOR 4 113 | 114 | 115 | /* made from pcap-linux.c and bpf/net/bpf.h */ 116 | 117 | #ifndef ARPHRD_IEEE80211_PRISM /* From Linux 2.4.18 */ 118 | #define ARPHRD_IEEE80211_PRISM 802 119 | #endif 120 | 121 | #define LINKTYPE_NULL 0 122 | #define LINKTYPE_ETHERNET 1 /* also for 100Mb and up */ 123 | #define LINKTYPE_EXP_ETHERNET 2 /* 3Mb experimental Ethernet */ 124 | #define LINKTYPE_AX25 3 125 | #define LINKTYPE_PRONET 4 126 | #define LINKTYPE_CHAOS 5 127 | #define LINKTYPE_TOKEN_RING 6 /* DLT_IEEE802 is used for Token Ring */ 128 | #define LINKTYPE_ARCNET 7 129 | #define LINKTYPE_SLIP 8 130 | #define LINKTYPE_PPP 9 131 | #define LINKTYPE_FDDI 10 132 | #define LINKTYPE_PPP_HDLC 50 /* PPP in HDLC-like framing */ 133 | #define LINKTYPE_PPP_ETHER 51 /* NetBSD PPP-over-Ethernet */ 134 | #define LINKTYPE_ATM_RFC1483 100 /* LLC/SNAP-encapsulated ATM */ 135 | #define LINKTYPE_RAW 101 /* raw IP */ 136 | #define LINKTYPE_SLIP_BSDOS 102 /* BSD/OS SLIP BPF header */ 137 | #define LINKTYPE_PPP_BSDOS 103 /* BSD/OS PPP BPF header */ 138 | #define LINKTYPE_C_HDLC 104 /* Cisco HDLC */ 139 | #define LINKTYPE_IEEE802_11 105 /* IEEE 802.11 (wireless) */ 140 | #define LINKTYPE_ATM_CLIP 106 /* Linux Classical IP over ATM */ 141 | #define LINKTYPE_LOOP 108 /* OpenBSD loopback */ 142 | #define LINKTYPE_LINUX_SLL 113 /* Linux cooked socket capture */ 143 | #define LINKTYPE_LTALK 114 /* Apple LocalTalk hardware */ 144 | #define LINKTYPE_ECONET 115 /* Acorn Econet */ 145 | #define LINKTYPE_CISCO_IOS 118 /* For Cisco-internal use */ 146 | #define LINKTYPE_PRISM_HEADER 119 /* 802.11+Prism II monitor mode */ 147 | #define LINKTYPE_AIRONET_HEADER 120 /* FreeBSD Aironet driver stuff */ 148 | 149 | int pcap_map[] = { ARPHRD_ETHER, LINKTYPE_ETHERNET, 150 | ARPHRD_METRICOM, LINKTYPE_ETHERNET, 151 | ARPHRD_LOOPBACK, LINKTYPE_ETHERNET, 152 | ARPHRD_EETHER, LINKTYPE_EXP_ETHERNET, 153 | ARPHRD_AX25, LINKTYPE_AX25, 154 | ARPHRD_PRONET, LINKTYPE_PRONET, 155 | ARPHRD_CHAOS, LINKTYPE_CHAOS, 156 | ARPHRD_IEEE802_TR, LINKTYPE_TOKEN_RING, 157 | ARPHRD_IEEE802, LINKTYPE_TOKEN_RING, 158 | ARPHRD_ARCNET, LINKTYPE_ARCNET, 159 | ARPHRD_FDDI, LINKTYPE_FDDI, 160 | ARPHRD_ATM, LINKTYPE_LINUX_SLL, 161 | ARPHRD_IEEE80211, LINKTYPE_IEEE802_11, 162 | ARPHRD_IEEE80211_PRISM, LINKTYPE_PRISM_HEADER, 163 | ARPHRD_PPP, LINKTYPE_RAW, 164 | ARPHRD_HDLC, LINKTYPE_C_HDLC, 165 | ARPHRD_TUNNEL, LINKTYPE_RAW, 166 | ARPHRD_SIT, LINKTYPE_RAW, 167 | ARPHRD_CSLIP, LINKTYPE_RAW, 168 | ARPHRD_SLIP6, LINKTYPE_RAW, 169 | ARPHRD_CSLIP6,LINKTYPE_RAW, 170 | ARPHRD_ADAPT, LINKTYPE_RAW, 171 | ARPHRD_SLIP, LINKTYPE_RAW, 172 | ARPHRD_RAWHDLC, LINKTYPE_RAW, 173 | ARPHRD_LOCALTLK, LINKTYPE_LTALK, 174 | 0, 0}; 175 | 176 | int arphdr_to_linktype(int arphdr) 177 | { 178 | int *p; 179 | 180 | for (p = pcap_map; *p; p += 2) 181 | if (*p == arphdr) 182 | return *(p+1); 183 | return -1; 184 | } 185 | 186 | void usage(void) 187 | { 188 | fprintf(stderr, IDENT 189 | "Usage: net2pcap -i interface [-pdx] [-f capfile] [-t ethertype] [-s snaplen] [-r newroot]\n" 190 | "\t-p : doesn't set promiscuous mode\n" 191 | "\t-d : daemon mode (background + uses syslog)\n" 192 | "\t-x : hexdumps every packet on output (if not daemon)\n" 193 | "\t-u : drop priviledges to UID\n" 194 | "\t-g : drop priviledges to GID\n" 195 | "\t-r : chroot into newroot\n" 196 | "\t snaplen defaults to %d\n" 197 | "\t capfile defaults to net2pcap.cap\n" 198 | "\t ethertype defaults to ETH_P_ALL (sniff all)\n", 199 | DEFAULT_SNAPLEN); 200 | exit(EXIT_FAILURE); 201 | } 202 | 203 | 204 | /* Hexdump functions */ 205 | 206 | int sane(unsigned char x) 207 | { 208 | return ((x >= 0x20) && (x < 0x80)); 209 | } 210 | 211 | void hexdump(void *buf, int len) 212 | { 213 | unsigned char *b = buf; 214 | int i,j; 215 | 216 | for (i=0; i < (len+15)/16*16; i++) { 217 | if (i < len) printf("%02x ",b[i]); else printf(" "); 218 | if (i%8 == 7) printf(" "); 219 | if (i%16 == 15) { 220 | for (j=i-15; (j < i) && (j < len); j++) 221 | printf("%c", sane(b[j]) ? b[j] : '.'); 222 | printf("\n"); 223 | } 224 | } 225 | } 226 | 227 | 228 | /* xwrite(): wrapper handling partial writes */ 229 | void xwrite(int fd, void *buf, size_t len) { 230 | ssize_t ret; 231 | size_t remaining = len; 232 | 233 | do { 234 | ret = write(fd, buf, remaining); 235 | if (ret == -1) { 236 | if (errno == EAGAIN || errno == EINTR) 237 | continue; 238 | else 239 | PERROR("write(buf)"); 240 | } 241 | remaining -= ret; 242 | buf += ret; 243 | } while (remaining > 0); 244 | } 245 | 246 | int only_digits(char *s) { 247 | char c; 248 | int nondigit_found = 0; 249 | 250 | while (c = *s++) { 251 | if (! isdigit(c)) { 252 | nondigit_found = 1; 253 | } 254 | } 255 | 256 | return !nondigit_found; 257 | } 258 | 259 | int term_received = 0, hup_received = 0; 260 | 261 | int main(int argc, char *argv[]) 262 | { 263 | int s, l, sigfd; 264 | int ptype = ETH_P_ALL; 265 | char *iff = NULL; 266 | char *newroot = NULL; 267 | char *fcap = "net2pcap.cap"; 268 | int promisc = 1; 269 | int ifidx = 0; 270 | char c; 271 | void *buf; 272 | size_t snaplen = DEFAULT_SNAPLEN; 273 | int f; 274 | struct sockaddr_ll sll; 275 | struct pcap_file_header hdr; 276 | struct pcap_pkthdr phdr; 277 | struct passwd *user_entry; 278 | struct group *group_entry; 279 | struct timeval native_tv; 280 | struct timezone tz; 281 | struct signalfd_siginfo sigfdinfo; 282 | sigset_t mask; 283 | int xdump = 0; 284 | unsigned long long int pktnb = 0; 285 | int linktype; 286 | uid_t uid = 0; 287 | gid_t gid = 0; 288 | fd_set readset; 289 | #if HAVE_SECCOMP_H 290 | scmp_filter_ctx ctx; 291 | #endif 292 | 293 | sigemptyset(&mask); 294 | sigaddset(&mask, SIGINT); 295 | sigaddset(&mask, SIGTERM); 296 | sigaddset(&mask, SIGQUIT); 297 | sigaddset(&mask, SIGHUP); 298 | 299 | if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) 300 | PERROR("sigprocmask()"); 301 | 302 | sigfd = signalfd(-1, &mask, 0); 303 | if (sigfd == -1) 304 | PERROR("signalfd()"); 305 | 306 | /* Get options */ 307 | 308 | while ((c = getopt(argc, argv, "dxhi:f:t:r:s:pu:g:")) != -1) { 309 | switch(c) { 310 | case 'h': 311 | usage(); 312 | case 'i': 313 | iff = optarg; 314 | break; 315 | case 'f': 316 | fcap = optarg; 317 | break; 318 | case 't': 319 | ptype = strtoul(optarg, NULL, 0); 320 | break; 321 | case 'p': 322 | promisc = 0; 323 | break; 324 | case 'r': 325 | newroot = optarg; 326 | break; 327 | case 's': 328 | errno = 0; 329 | snaplen = strtoul(optarg, NULL,0); 330 | if (errno) 331 | PERROR("invalid snaplen"); 332 | break; 333 | case 'd': 334 | daemonize = 1; 335 | break; 336 | case 'u': 337 | errno = 0; 338 | if (only_digits(optarg)) { 339 | uid = strtoul(optarg, NULL, 0); 340 | if (errno) { 341 | PERROR("Invalid uid"); 342 | } 343 | } else { 344 | errno = 0; 345 | user_entry = getpwnam(optarg); 346 | if (user_entry == NULL) { 347 | if (errno) { 348 | PERROR("getpwent()"); 349 | } else { 350 | ERROR("Username not found\n"); 351 | } 352 | } 353 | uid = user_entry->pw_uid; 354 | } 355 | break; 356 | case 'g': 357 | errno = 0; 358 | if (only_digits(optarg)) { 359 | gid = strtoul(optarg, NULL, 0); 360 | if (errno) { 361 | ERROR("Invalid gid"); 362 | } 363 | } else { 364 | errno = 0; 365 | group_entry = getgrnam(optarg); 366 | if (group_entry == NULL) { 367 | if (errno) { 368 | PERROR("getgrnam()"); 369 | } else { 370 | ERROR("Group name not found\n"); 371 | } 372 | } 373 | gid = group_entry->gr_gid; 374 | } 375 | break; 376 | case 'x': 377 | xdump = 1; 378 | break; 379 | default: 380 | printf("Error!\n"); 381 | usage(); 382 | } 383 | } 384 | 385 | if (!iff) ERROR ("No interface specified\n"); 386 | 387 | buf = malloc(snaplen); 388 | if (!buf) PERROR("malloc"); 389 | 390 | /* Prepare socket according to options */ 391 | 392 | s = socket(PF_PACKET, SOCK_RAW, htons(ptype)); 393 | if (s == -1) PERROR("socket"); 394 | 395 | if (iff) { 396 | struct ifreq ifr; 397 | strncpy(ifr.ifr_name, iff, IF_NAMESIZE); 398 | if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) PERROR("ioctl"); 399 | ifidx = ifr.ifr_ifindex; 400 | } 401 | 402 | if (promisc) { 403 | struct packet_mreq mreq; 404 | mreq.mr_ifindex = ifidx; 405 | mreq.mr_type = PACKET_MR_PROMISC; 406 | mreq.mr_alen = 0; 407 | if (setsockopt(s, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) 408 | PERROR("setsockopt"); 409 | } 410 | 411 | if (ifidx || (ptype != ETH_P_ALL)) { 412 | sll.sll_family = AF_PACKET; 413 | sll.sll_protocol = htons(ptype); 414 | sll.sll_ifindex = ifidx; 415 | if (bind(s, (struct sockaddr *)&sll, sizeof(sll)) == -1) PERROR("bind"); 416 | } 417 | 418 | l = sizeof(sll); 419 | if (getsockname(s, (struct sockaddr *)&sll, &l) == -1) 420 | PERROR("getsockname"); 421 | linktype = arphdr_to_linktype(sll.sll_hatype); 422 | 423 | if (daemonize) { 424 | openlog("net2pcap", LOG_PID|LOG_NDELAY, LOG_DAEMON); 425 | if (daemon(0, 0) != 0) 426 | PERROR("daemon()"); 427 | daemonize++; 428 | } 429 | 430 | if (newroot) { 431 | if (chroot(newroot) != 0) 432 | PERROR("chroot"); 433 | if (chdir("/") != 0) 434 | PERROR("chdir(/)"); 435 | } 436 | 437 | if (uid && !gid) { 438 | /* 439 | * uid set but gid not, good behavior is to 440 | * set gid to primary group of uid 441 | */ 442 | errno = 0; 443 | user_entry = getpwuid(uid); 444 | if (!user_entry) { 445 | if (errno) 446 | PERROR("getpwuid()"); 447 | else 448 | ERROR("uid %d does not exist," 449 | " cannot find primary group\n", 450 | uid); 451 | } 452 | gid = user_entry->pw_gid; 453 | } 454 | 455 | if (gid && (setgid(gid) == -1)) 456 | PERROR("setgid()"); 457 | 458 | if (uid && (setuid(uid) == -1)) 459 | PERROR("setuid()"); 460 | 461 | #if HAVE_SECCOMP_H 462 | ctx = seccomp_init(SCMP_ACT_KILL); 463 | 464 | if (ctx == NULL) 465 | ERROR("Cannot go into SECCOMPv2"); 466 | 467 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 1, 468 | SCMP_A1(SCMP_CMP_EQ, O_CREAT|O_WRONLY|O_APPEND|O_LARGEFILE)); 469 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketcall), 0); 470 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0); 471 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0); 472 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(gettimeofday), 0); 473 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0); 474 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0); 475 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(_llseek), 0); 476 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(_newselect), 0); 477 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); 478 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0); 479 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sigreturn), 0); 480 | 481 | if (daemonize) { 482 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(time), 0); 483 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat64), 0); 484 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2), 0); 485 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(munmap), 0); 486 | } 487 | 488 | if (seccomp_load(ctx) < 0) 489 | ERROR("Cannot load SECCOMP filters"); 490 | 491 | LOG(LOG_INFO,"Started [sandboxed].\n"); 492 | seccomp_release(ctx); 493 | #else 494 | LOG(LOG_INFO,"Started.\n"); 495 | #endif /* HAVE_SECCOMP_H */ 496 | 497 | 498 | while (!term_received) { /* Main loop */ 499 | off_t filepos; 500 | /* Prepare capture file */ 501 | f = open(fcap, O_CREAT|O_WRONLY|O_APPEND, CRATIONMASK); 502 | if (f == -1) PERROR("open(append)"); 503 | filepos = lseek(f, 0, SEEK_END); 504 | if (filepos == -1) PERROR("lseek"); 505 | if (!filepos) { /* Empty file --> add header */ 506 | LOG(LOG_NOTICE, "Creating capture file %s\n", fcap); 507 | if (gettimeofday(&native_tv, &tz) == -1) PERROR("gettimeofday"); 508 | hdr.magic = PCAP_MAGIC; 509 | hdr.version_major = PCAP_VERSION_MAJOR; 510 | hdr.version_minor = PCAP_VERSION_MINOR; 511 | hdr.thiszone = tz.tz_dsttime; /* XXX */ 512 | hdr.sigfigs = 0; 513 | hdr.snaplen = snaplen; 514 | hdr.linktype = linktype; 515 | xwrite(f, &hdr, sizeof(hdr)); 516 | } else 517 | LOG(LOG_NOTICE, "Appending to capture file %s\n", fcap); 518 | 519 | hup_received = 0; 520 | pktnb = 0; 521 | while (!hup_received && !term_received) { /* Receive loop */ 522 | FD_ZERO(&readset); 523 | FD_SET(s, &readset); 524 | FD_SET(sigfd, &readset); 525 | 526 | if (select(MAX(s, sigfd) + 1, &readset, NULL, NULL, NULL) == -1) 527 | PERROR("select()"); 528 | 529 | if (FD_ISSET(s, &readset)) 530 | { 531 | ssize_t rcvdlen = recv(s, buf, snaplen, 0); 532 | if (rcvdlen == -1) 533 | PERROR("recv"); 534 | if (xdump && !daemonize) 535 | hexdump(buf, rcvdlen); 536 | gettimeofday(&native_tv, NULL); 537 | 538 | phdr.ts.tv_sec = NATIVE2COMPAT(native_tv.tv_sec); 539 | phdr.ts.tv_usec = NATIVE2COMPAT(native_tv.tv_usec); 540 | 541 | phdr.len = rcvdlen; 542 | phdr.caplen = rcvdlen; 543 | 544 | xwrite(f, &phdr, sizeof(phdr)); 545 | xwrite(f, buf, rcvdlen); 546 | pktnb++; 547 | } 548 | 549 | if (FD_ISSET(sigfd, &readset)) 550 | { 551 | if (read(sigfd, &sigfdinfo, sizeof(sigfdinfo)) != sizeof(sigfdinfo)) 552 | PERROR("read(signalfd_siginfo)"); 553 | 554 | switch (sigfdinfo.ssi_signo) 555 | { 556 | case SIGINT: 557 | case SIGTERM: 558 | term_received = 1; 559 | break; 560 | case SIGHUP: 561 | hup_received = 1; 562 | break; 563 | default: 564 | ERROR("signal %d received", sigfdinfo.ssi_signo); 565 | } 566 | } 567 | } 568 | LOG(LOG_INFO,"Received %lld packets\n", pktnb); 569 | if (close(f) == -1) PERROR("close"); 570 | } 571 | if (daemonize) closelog(); 572 | LOG(LOG_INFO,"Stopped.\n"); 573 | exit(EXIT_SUCCESS); 574 | } 575 | --------------------------------------------------------------------------------