├── .gitignore ├── LICENSE.txt ├── Makefile ├── README.md ├── pcap-bad-udp-checksum.c ├── pcap-change-dst.c ├── pcap-change-ip.c ├── pcap-change-port.c ├── pcap-decapsulate-gre.c ├── pcap-dns-find-edns-opt.c ├── pcap-extract-interval.c ├── pcap-find-misordered.c ├── pcap-fix-linux-af-inet6.c ├── pcap-join.c ├── pcap-merge-sorted-sip.c ├── pcap-print-sip-protocol.c ├── pcap-print-sip.c ├── pcap-print-tcp-options.c ├── pcap-print-time-qname-qtype-rcode.c ├── pcap-remove-bogus.c ├── pcap-remove-dupe.c ├── pcap-reorder.c ├── pcap-sample.c ├── pcap-separate-by-connection.c ├── pcap-separate-by-sip.c ├── pcap-separate.c ├── pcap-sort-by-sip.c ├── pcap-split.c ├── pcap-strip-vlans.c ├── pcap-subtract-timestamp.c ├── pcap-to-dlt-en10mb.c ├── pcap-to-dlt-loop.c ├── pcap-to-dlt-raw.c ├── pcap-tools.c └── pcap-tools.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | pcap-change-dst 3 | pcap-change-ip 4 | pcap-decapsulate-gre 5 | pcap-extract-interval 6 | pcap-find-misordered 7 | pcap-fix-linux-af-inet6 8 | pcap-join 9 | pcap-merge-sorted-sip 10 | pcap-print-sip 11 | pcap-print-sip-protocol 12 | pcap-print-tcp-options 13 | pcap-remove-bogus 14 | pcap-remove-dupe 15 | pcap-reorder 16 | pcap-separate 17 | pcap-separate-by-connection 18 | pcap-separate-by-sip 19 | pcap-sort-by-sip 20 | pcap-split 21 | pcap-strip-vlans 22 | pcap-subtract-timestamp 23 | pcap-to-dlt-en10mb 24 | pcap-to-dlt-loop 25 | pcap-to-dlt-raw 26 | pcap-bad-udp-checksum 27 | pcap-change-port 28 | pcap-dns-find-edns-opt 29 | pcap-print-time-qname-qtype-rcode 30 | pcap-sample 31 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Duane Wessels and The Measurement Factory, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PREFIX=${HOME} 2 | OBJS=\ 3 | pcap-tools.o 4 | 5 | PROGS= \ 6 | pcap-extract-interval \ 7 | pcap-subtract-timestamp \ 8 | pcap-join \ 9 | pcap-remove-dupe \ 10 | pcap-remove-bogus \ 11 | pcap-split \ 12 | pcap-sample \ 13 | pcap-change-dst \ 14 | pcap-change-ip \ 15 | pcap-change-port \ 16 | pcap-decapsulate-gre \ 17 | pcap-find-misordered \ 18 | pcap-reorder \ 19 | pcap-fix-linux-af-inet6 \ 20 | pcap-strip-vlans \ 21 | pcap-print-sip \ 22 | pcap-print-tcp-options \ 23 | pcap-print-sip-protocol \ 24 | pcap-print-time-qname-qtype-rcode \ 25 | pcap-separate-by-sip \ 26 | pcap-separate-by-connection \ 27 | pcap-sort-by-sip \ 28 | pcap-merge-sorted-sip \ 29 | pcap-separate \ 30 | pcap-to-dlt-loop \ 31 | pcap-to-dlt-raw \ 32 | pcap-to-dlt-en10mb \ 33 | pcap-bad-udp-checksum \ 34 | pcap-dns-find-edns-opt \ 35 | #pcap-print-time-sip-len \ 36 | 37 | LIBPCAP=-lpcap 38 | 39 | LIBPCAPLAYERS=-L${PREFIX}/lib -lpcap_layers 40 | 41 | # BSD 42 | #LIBMD5=-lmd 43 | #INCDIRS= 44 | 45 | # LINUX 46 | LIBMD5=-lcrypto 47 | INCDIRS=-I${PREFIX}/include 48 | 49 | CFLAGS = -Wall -g ${INCDIRS} 50 | 51 | all: ${PROGS} 52 | 53 | pcap-tools.o: pcap-tools.c pcap-tools.h 54 | ${CC} -c -o $@ pcap-tools.c 55 | 56 | 57 | pcap-extract-interval: pcap-extract-interval.o ${OBJS} 58 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} 59 | 60 | pcap-subtract-timestamp: pcap-subtract-timestamp.o ${OBJS} 61 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} 62 | 63 | pcap-join: pcap-join.o ${OBJS} 64 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} 65 | 66 | pcap-remove-dupe: pcap-remove-dupe.o ${OBJS} 67 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} ${LIBMD5} 68 | 69 | pcap-remove-bogus: pcap-remove-bogus.o ${OBJS} 70 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} 71 | 72 | pcap-split: pcap-split.o ${OBJS} 73 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} 74 | 75 | pcap-change-dst: pcap-change-dst.o ${OBJS} 76 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} ${LIBPCAPLAYERS} 77 | 78 | pcap-change-ip: pcap-change-ip.o ${OBJS} 79 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} ${LIBPCAPLAYERS} 80 | 81 | pcap-change-port: pcap-change-port.o ${OBJS} 82 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} ${LIBPCAPLAYERS} 83 | 84 | pcap-decapsulate-gre: pcap-decapsulate-gre.o ${OBJS} 85 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} ${LIBPCAPLAYERS} 86 | 87 | pcap-find-misordered: pcap-find-misordered.o ${OBJS} 88 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} 89 | 90 | pcap-reorder: pcap-reorder.o ${OBJS} 91 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} ${LIBPCAPLAYERS} 92 | 93 | pcap-fix-linux-af-inet6: pcap-fix-linux-af-inet6.o ${OBJS} 94 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} 95 | 96 | pcap-strip-vlans: pcap-strip-vlans.o ${OBJS} 97 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} 98 | 99 | pcap-print-sip: pcap-print-sip.o ${OBJS} 100 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} ${LIBPCAPLAYERS} 101 | 102 | pcap-print-tcp-options: pcap-print-tcp-options.o ${OBJS} 103 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} ${LIBPCAPLAYERS} 104 | 105 | pcap-print-sip-protocol: pcap-print-sip-protocol.o ${OBJS} 106 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} ${LIBPCAPLAYERS} 107 | 108 | pcap-separate-by-sip: pcap-separate-by-sip.o ${OBJS} 109 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} ${LIBPCAPLAYERS} 110 | 111 | pcap-separate-by-connection: pcap-separate-by-connection.o ${OBJS} 112 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} ${LIBPCAPLAYERS} 113 | 114 | pcap-sort-by-sip: pcap-sort-by-sip.o ${OBJS} 115 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} ${LIBPCAPLAYERS} 116 | 117 | pcap-separate: pcap-separate.o ${OBJS} 118 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} ${LIBPCAPLAYERS} 119 | 120 | pcap-to-dlt-loop: pcap-to-dlt-loop.o ${OBJS} 121 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} ${LIBPCAPLAYERS} 122 | 123 | pcap-to-dlt-raw: pcap-to-dlt-raw.o ${OBJS} 124 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} ${LIBPCAPLAYERS} 125 | 126 | pcap-to-dlt-en10mb: pcap-to-dlt-en10mb.o ${OBJS} 127 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} ${LIBPCAPLAYERS} 128 | 129 | pcap-merge-sorted-sip: pcap-merge-sorted-sip.o ${OBJS} 130 | ${CC} -o $@ ${@}.o ${OBJS} ${LIBPCAP} ${LIBPCAPLAYERS} 131 | 132 | #pcap-print-time-sip-len: pcap-print-time-sip-len.o 133 | #${CC} -o $@ ${@}.o ${LIBPCAP} ${LIBPCAPLAYERS} 134 | 135 | pcap-print-time-qname-qtype-rcode: pcap-print-time-qname-qtype-rcode.o 136 | ${CC} -o $@ ${@}.o ${LIBPCAP} ${LIBPCAPLAYERS} -lldns 137 | 138 | pcap-bad-udp-checksum: pcap-bad-udp-checksum.o 139 | ${CC} -o $@ ${@}.o ${LIBPCAP} ${LIBPCAPLAYERS} -linx_addr_c 140 | 141 | pcap-dns-find-edns-opt: pcap-dns-find-edns-opt.o 142 | ${CC} -o $@ ${@}.o ${LIBPCAP} ${OBJS} ${LIBPCAPLAYERS} -lldns 143 | 144 | pcap-sample: pcap-sample.o ${OBJS} 145 | ${CC} -o $@ ${@}.o ${LIBPCAP} ${OBJS} 146 | 147 | 148 | clean: 149 | @for f in ${PROGS}; do \ 150 | rm -fv $$f.o $$f ; \ 151 | done 152 | rm -fv ${OBJS} 153 | 154 | install: 155 | @for f in ${PROGS}; do \ 156 | echo "install -C -m 755 $$f ${PREFIX}/bin"; \ 157 | install -C -m 755 $$f ${PREFIX}/bin ; \ 158 | done 159 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | pcap-tools 2 | ========== 3 | 4 | A suite of command line tools for manipulating pcap files 5 | 6 | 7 | ## Dependencies 8 | 9 | Nearly all of these require: 10 | * libpcap 11 | * [pcap_layers](https://github.com/wessels/pcap_layers) 12 | * [inx_addr](https://github.com/wessels/inx_addr) 13 | 14 | Some also require 15 | * ldns 16 | * openssl 17 | -------------------------------------------------------------------------------- /pcap-bad-udp-checksum.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include "pcap-tools.h" 19 | 20 | const char *progname; 21 | 22 | struct state 23 | { 24 | inx_addr src; 25 | inx_addr dst; 26 | int proto; 27 | int frag; 28 | int cksum_bad; 29 | }; 30 | 31 | unsigned short 32 | in_cksum(unsigned short *ptr, int size, unsigned int sum) 33 | { 34 | unsigned short oddbyte; 35 | unsigned short answer; 36 | while (size > 1) { 37 | sum += *ptr++; 38 | size -= 2; 39 | } 40 | if (size == 1) { 41 | oddbyte = 0; 42 | *((unsigned char *) &oddbyte) = *(unsigned char *) ptr; 43 | sum += oddbyte; 44 | } 45 | sum = (sum >> 16) + (sum & 0xffff); 46 | sum += (sum >> 16); 47 | answer = ~sum; 48 | return answer; 49 | } 50 | 51 | int 52 | my_udp_handler(const struct udphdr *udp, int len, void *userdata) 53 | { 54 | unsigned short pseudo[18]; 55 | unsigned int ps = 0; 56 | struct state *s = userdata; 57 | unsigned int i; 58 | s->proto = 17; 59 | if (s->frag) 60 | return 0; 61 | #ifdef __linux__ 62 | if (0 == udp->check) 63 | return 0; 64 | #else 65 | if (0 == udp->uh_sum) 66 | return 0; 67 | #endif 68 | memset(&pseudo[0], 0, sizeof(pseudo)); 69 | if (4 == inx_addr_version(&s->src)) { 70 | memcpy(&pseudo[0], &s->src._.in4, 4); 71 | memcpy(&pseudo[8], &s->dst._.in4, 4); 72 | } else if (6 == inx_addr_version(&s->src)) { 73 | memcpy(&pseudo[0], &s->src.in6, 16); 74 | memcpy(&pseudo[8], &s->dst.in6, 16); 75 | } 76 | pseudo[16] = htons(IPPROTO_UDP); 77 | pseudo[17] = htons((unsigned short) len); 78 | for (i = 0; i < sizeof(pseudo) / sizeof(unsigned short); i++) 79 | ps += pseudo[i]; 80 | unsigned int calc_sum = in_cksum((unsigned short *) udp, len, ps); 81 | if (0 != calc_sum) 82 | s->cksum_bad = 1; 83 | return 0; 84 | } 85 | 86 | /* 87 | * this will only be called if 'ip' is a complete IPv header 88 | */ 89 | int 90 | my_ip4_handler(const struct ip *ip4, int len, void *userdata) 91 | { 92 | struct state *s = userdata; 93 | uint16_t ip_off = ntohs(ip4->ip_off); 94 | inx_addr_assign_v4(&s->src, &ip4->ip_src); 95 | inx_addr_assign_v4(&s->dst, &ip4->ip_dst); 96 | if ((ip_off & IP_MF) || 0 != (ip_off & IP_OFFMASK)) 97 | s->frag = 1; 98 | return 0; 99 | } 100 | 101 | int 102 | my_ip6_handler(const struct ip6_hdr *ip6, int len, void *userdata) 103 | { 104 | struct state *s = userdata; 105 | inx_addr_assign_v6(&s->src, &ip6->ip6_src); 106 | inx_addr_assign_v6(&s->dst, &ip6->ip6_dst); 107 | return 0; 108 | } 109 | 110 | int 111 | main(int argc, char *argv[]) 112 | { 113 | pcap_t *in = NULL; 114 | char errbuf[PCAP_ERRBUF_SIZE + 1]; 115 | struct pcap_pkthdr hdr; 116 | const u_char *data; 117 | pcap_dumper_t *out = NULL; 118 | struct state S; 119 | 120 | progname = argv[0]; 121 | if (argc < 2) { 122 | fprintf(stderr, "usage: %s pcapfiles\n", progname); 123 | exit(1); 124 | } 125 | 126 | in = pcap_open_offline(argv[1], errbuf); 127 | if (NULL == in) { 128 | fprintf(stderr, "%s: %s", argv[1], errbuf); 129 | exit(1); 130 | } 131 | out = pcap_dump_open(in, "-"); 132 | if (NULL == out) { 133 | perror("stdout"); 134 | exit(1); 135 | } 136 | pcap_layers_init(pcap_datalink(in), 0); 137 | callback_ipv4 = my_ip4_handler; 138 | callback_ipv6 = my_ip6_handler; 139 | callback_udp = my_udp_handler; 140 | while ((data = pcap_next(in, &hdr))) { 141 | memset(&S, 0, sizeof(S)); 142 | handle_pcap((u_char *) & S, &hdr, data); 143 | if (17 == S.proto && 1 == S.cksum_bad) 144 | pcap_dump((void *) out, &hdr, data); 145 | } 146 | pcap_close(in); 147 | pcap_dump_close(out); 148 | exit(0); 149 | } 150 | -------------------------------------------------------------------------------- /pcap-change-dst.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "pcap_layers.h" 17 | 18 | struct in_addr dst4; 19 | struct in6_addr dst6; 20 | 21 | /* 22 | * this will only be called if 'ip' is a complete IPv header 23 | */ 24 | int 25 | my_ip4_handler(const struct ip *ip4, int len, void *userdata) 26 | { 27 | memcpy((void *) &ip4->ip_dst, &dst4, sizeof(dst4)); 28 | return 0; 29 | } 30 | 31 | int 32 | my_ip6_handler(const struct ip6_hdr *ip6, int len, void *userdata) 33 | { 34 | memcpy((void *) &ip6->ip6_dst, &dst6, sizeof(dst6)); 35 | return 0; 36 | } 37 | 38 | int 39 | main(int argc, char *argv[]) 40 | { 41 | pcap_t *in = NULL; 42 | pcap_dumper_t *out = NULL; 43 | char errbuf[PCAP_ERRBUF_SIZE + 1]; 44 | struct pcap_pkthdr hdr; 45 | const u_char *data; 46 | 47 | 48 | if (argc < 2) { 49 | fprintf(stderr, "usage: pcap-change-dst dst-ipv4 dst-ipv6\n"); 50 | exit(1); 51 | } 52 | if (inet_pton(AF_INET, argv[1], &dst4) != 1) { 53 | fprintf(stderr, "bad IPv4 address: %s\n", argv[1]); 54 | exit(1); 55 | } 56 | if (inet_pton(AF_INET6, argv[2], &dst6) != 1) { 57 | fprintf(stderr, "bad IPv6 address: %s\n", argv[2]); 58 | exit(1); 59 | } 60 | 61 | in = pcap_open_offline("-", errbuf); 62 | if (NULL == in) { 63 | fprintf(stderr, "stdin: %s", errbuf); 64 | exit(1); 65 | } 66 | out = pcap_dump_open(in, "-"); 67 | if (NULL == out) { 68 | perror("stdout"); 69 | exit(1); 70 | } 71 | pcap_layers_init(pcap_datalink(in), 0); 72 | callback_ipv4 = my_ip4_handler; 73 | callback_ipv6 = my_ip6_handler; 74 | while ((data = pcap_next(in, &hdr))) { 75 | handle_pcap(NULL, &hdr, data); 76 | pcap_dump((void *) out, &hdr, data); 77 | } 78 | pcap_close(in); 79 | pcap_dump_close(out); 80 | exit(0); 81 | } 82 | -------------------------------------------------------------------------------- /pcap-change-ip.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pcap-change-ip 3 | * 4 | * If either src/dst IP falls within the given network, the IP will be 5 | * changed to a new value. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "pcap_layers.h" 24 | 25 | struct in_addr old4; 26 | struct in_addr mask4; 27 | struct in_addr to4; 28 | struct in6_addr old6; 29 | struct in6_addr mask6; 30 | struct in6_addr to6; 31 | 32 | int 33 | match4(struct in_addr check) 34 | { 35 | if ((check.s_addr & mask4.s_addr) != old4.s_addr) 36 | return 0; 37 | return 1; 38 | } 39 | 40 | int 41 | match6(struct in6_addr check) 42 | { 43 | int k; 44 | for (k = 0; k < 16; k++) 45 | if ((check.s6_addr[k] & mask6.s6_addr[k]) != old6.s6_addr[k]) 46 | return 0; 47 | return 1; 48 | } 49 | 50 | /* 51 | * this will only be called if 'ip' is a complete IPv header 52 | */ 53 | int 54 | my_ip4_handler(const struct ip *ip4, int len, void *userdata) 55 | { 56 | if (match4(ip4->ip_src)) 57 | memcpy((void *) &ip4->ip_src, &to4, sizeof(to4)); 58 | if (match4(ip4->ip_dst)) 59 | memcpy((void *) &ip4->ip_dst, &to4, sizeof(to4)); 60 | return 0; 61 | } 62 | 63 | int 64 | my_ip6_handler(const struct ip6_hdr *ip6, int len, void *userdata) 65 | { 66 | if (match6(ip6->ip6_src)) 67 | memcpy((void *) &ip6->ip6_src, &to6, sizeof(to6)); 68 | if (match6(ip6->ip6_dst)) 69 | memcpy((void *) &ip6->ip6_dst, &to6, sizeof(to6)); 70 | return 0; 71 | } 72 | 73 | void 74 | usage(void) 75 | { 76 | fprintf(stderr, "usage: pcap-change-ip from-ip4/prefixlen new-ip4 from-ip6/prefixlen new-ip6\n"); 77 | exit(1); 78 | } 79 | 80 | int 81 | main(int argc, char *argv[]) 82 | { 83 | pcap_t *in = NULL; 84 | pcap_dumper_t *out = NULL; 85 | char errbuf[PCAP_ERRBUF_SIZE + 1]; 86 | struct pcap_pkthdr hdr; 87 | const u_char *data; 88 | char *t; 89 | unsigned int ml; 90 | unsigned int k; 91 | 92 | 93 | if (argc < 5) 94 | usage(); 95 | if (NULL == (t = strchr(argv[1], '/'))) 96 | usage(); 97 | *t = 0; 98 | if (inet_pton(AF_INET, argv[1], &old4) != 1) { 99 | fprintf(stderr, "bad IPv4 address: %s\n", argv[1]); 100 | usage(); 101 | } 102 | ml = atoi(t + 1); 103 | if (ml > 32) { 104 | fprintf(stderr, "IPv4 prefixlen (%u) out of range\n", ml); 105 | usage(); 106 | } 107 | mask4.s_addr = htonl(~0 << (32 - ml)); 108 | if (inet_pton(AF_INET, argv[2], &to4) != 1) { 109 | fprintf(stderr, "bad IPv4 address: %s\n", argv[2]); 110 | usage(); 111 | } 112 | if (NULL == (t = strchr(argv[3], '/'))) 113 | usage(); 114 | *t = 0; 115 | if (inet_pton(AF_INET6, argv[3], &old6) != 1) { 116 | fprintf(stderr, "bad IPv6 address: %s\n", argv[3]); 117 | exit(1); 118 | } 119 | ml = atoi(t + 1); 120 | if (ml > 128) { 121 | fprintf(stderr, "IPv6 prefixlen (%u) out of range\n", ml); 122 | usage(); 123 | } 124 | memset(&mask6, 0, sizeof(mask6)); 125 | for (k = 0; k < 16; k++, ml -= 8) { 126 | if (ml >= 8) { 127 | mask6.s6_addr[k] = 0xff; 128 | } else { 129 | mask6.s6_addr[k] = 0xff << (8 - ml); 130 | break; 131 | } 132 | } 133 | if (inet_pton(AF_INET6, argv[4], &to6) != 1) { 134 | fprintf(stderr, "bad IPv6 address: %s\n", argv[4]); 135 | usage(); 136 | } 137 | 138 | in = pcap_open_offline("-", errbuf); 139 | if (NULL == in) { 140 | fprintf(stderr, "stdin: %s", errbuf); 141 | exit(1); 142 | } 143 | out = pcap_dump_open(in, "-"); 144 | if (NULL == out) { 145 | perror("stdout"); 146 | exit(1); 147 | } 148 | pcap_layers_init(pcap_datalink(in), 0); 149 | callback_ipv4 = my_ip4_handler; 150 | callback_ipv6 = my_ip6_handler; 151 | while ((data = pcap_next(in, &hdr))) { 152 | handle_pcap(NULL, &hdr, data); 153 | pcap_dump((void *) out, &hdr, data); 154 | } 155 | pcap_close(in); 156 | pcap_dump_close(out); 157 | exit(0); 158 | } 159 | -------------------------------------------------------------------------------- /pcap-change-port.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pcap-change-port 3 | * 4 | * Change UDP/TCP port of some packets. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "pcap-tools.h" 23 | #include "pcap_layers.h" 24 | 25 | unsigned short oldport = 0; 26 | unsigned short newport = 0; 27 | 28 | int 29 | my_udp_handler(struct udphdr *udp, int len, void *userdata) 30 | { 31 | if (nptohs(&udp->uh_sport) == oldport) 32 | udp->uh_sport = ntohs(newport); 33 | if (nptohs(&udp->uh_dport) == oldport) 34 | udp->uh_dport = ntohs(newport); 35 | return 0; 36 | } 37 | 38 | int 39 | my_tcp_handler(struct tcphdr *tcp, int len, void *userdata) 40 | { 41 | if (nptohs(&tcp->th_sport) == oldport) 42 | tcp->th_sport = ntohs(newport); 43 | if (nptohs(&tcp->th_dport) == oldport) 44 | tcp->th_dport = ntohs(newport); 45 | return 0; 46 | } 47 | 48 | void 49 | usage(void) 50 | { 51 | fprintf(stderr, "usage: pcap-change-ip old-port new-port\n"); 52 | exit(1); 53 | } 54 | 55 | int 56 | main(int argc, char *argv[]) 57 | { 58 | pcap_t *in = NULL; 59 | pcap_dumper_t *out = NULL; 60 | char errbuf[PCAP_ERRBUF_SIZE + 1]; 61 | struct pcap_pkthdr hdr; 62 | const u_char *data; 63 | 64 | if (argc < 3) 65 | usage(); 66 | if ((oldport = strtoul(argv[1], 0, 10)) == 0) { 67 | fprintf(stderr, "bad old-port : %s\n", argv[1]); 68 | usage(); 69 | } 70 | if ((newport = strtoul(argv[2], 0, 10)) == 0) { 71 | fprintf(stderr, "bad new-port : %s\n", argv[2]); 72 | usage(); 73 | } 74 | 75 | in = pcap_open_offline("-", errbuf); 76 | if (NULL == in) { 77 | fprintf(stderr, "stdin: %s", errbuf); 78 | exit(1); 79 | } 80 | out = pcap_dump_open(in, "-"); 81 | if (NULL == out) { 82 | perror("stdout"); 83 | exit(1); 84 | } 85 | pcap_layers_init(pcap_datalink(in), 0); 86 | callback_udp = (int (*)(const struct udphdr *, int, void *)) my_udp_handler; 87 | callback_tcp = (int (*)(const struct tcphdr *, int, void *)) my_tcp_handler; 88 | while ((data = pcap_next(in, &hdr))) { 89 | handle_pcap(NULL, &hdr, data); 90 | pcap_dump((void *) out, &hdr, data); 91 | } 92 | pcap_close(in); 93 | pcap_dump_close(out); 94 | exit(0); 95 | } 96 | -------------------------------------------------------------------------------- /pcap-decapsulate-gre.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "pcap_layers.h" 18 | 19 | struct _state 20 | { 21 | int from_gre; 22 | void *ip_start; 23 | int ip_len; 24 | void *gre_start; 25 | int gre_len; 26 | }; 27 | 28 | /* 29 | * this will only be called if 'ip' is a complete IPv4 header 30 | */ 31 | int 32 | my_ip4_handler(const struct ip *ip4, int len, void *userdata) 33 | { 34 | struct _state *s = userdata; 35 | if (!s->from_gre) { 36 | s->ip_start = (void *) ip4; 37 | s->ip_len = len; 38 | } else { 39 | s->gre_start = (void *) ip4; 40 | s->gre_len = len; 41 | } 42 | return 0; 43 | } 44 | 45 | int 46 | my_ip6_handler(const struct ip6_hdr *ip6, int len, void *userdata) 47 | { 48 | struct _state *s = userdata; 49 | if (!s->from_gre) { 50 | s->ip_start = (void *) ip6; 51 | s->ip_len = len; 52 | } else { 53 | s->gre_start = (void *) ip6; 54 | s->gre_len = len; 55 | } 56 | return 0; 57 | } 58 | 59 | int 60 | my_gre_handler(const unsigned char *pkt, int len, void *userdata) 61 | { 62 | struct _state *s = userdata; 63 | s->from_gre = 1; 64 | return 0; 65 | } 66 | 67 | int 68 | main(int argc, char *argv[]) 69 | { 70 | pcap_t *in = NULL; 71 | pcap_dumper_t *out = NULL; 72 | char errbuf[PCAP_ERRBUF_SIZE + 1]; 73 | struct pcap_pkthdr hdr; 74 | const u_char *data; 75 | struct _state s; 76 | 77 | 78 | in = pcap_open_offline("-", errbuf); 79 | if (NULL == in) { 80 | fprintf(stderr, "stdin: %s", errbuf); 81 | exit(1); 82 | } 83 | out = pcap_dump_open(in, "-"); 84 | if (NULL == out) { 85 | perror("stdout"); 86 | exit(1); 87 | } 88 | pcap_layers_init(pcap_datalink(in), 0); 89 | callback_ipv4 = my_ip4_handler; 90 | callback_ipv6 = my_ip6_handler; 91 | callback_gre = my_gre_handler; 92 | while ((data = pcap_next(in, &hdr))) { 93 | memset(&s, 0, sizeof(s)); 94 | handle_pcap((void *) &s, &hdr, data); 95 | if (s.from_gre && s.ip_start && s.gre_start && s.ip_start < s.gre_start && s.ip_len && s.gre_len 96 | && s.ip_len > s.gre_len) { 97 | int chop = (s.gre_start - s.ip_start); 98 | hdr.caplen -= chop; 99 | hdr.len -= chop; 100 | memmove(s.ip_start, s.gre_start, s.gre_len); 101 | pcap_dump((void *) out, &hdr, data); 102 | } 103 | } 104 | pcap_close(in); 105 | pcap_dump_close(out); 106 | exit(0); 107 | } 108 | -------------------------------------------------------------------------------- /pcap-dns-find-edns-opt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include "pcap-tools.h" 20 | 21 | #include 22 | 23 | const char *progname = 0; 24 | unsigned int only_option_code = 0; 25 | unsigned int verbose = 0; 26 | 27 | int 28 | my_dns_handler(const u_char * buf, int len, void *userdata) 29 | { 30 | int *flag = userdata; 31 | ldns_pkt *pkt = 0; 32 | if (LDNS_STATUS_OK != ldns_wire2pkt(&pkt, buf, len)) 33 | goto done; 34 | 35 | ldns_rdf *opt = ldns_pkt_edns_data(pkt); 36 | if (0 == opt) 37 | goto done; 38 | if (LDNS_RDF_TYPE_UNKNOWN != ldns_rdf_get_type(opt)) 39 | goto done; 40 | unsigned short rdata_len = ldns_rdf_size(opt); 41 | unsigned char *rdata = ldns_rdf_data(opt); 42 | while (rdata_len >= 4) { 43 | unsigned short option_code = nptohs(rdata); 44 | unsigned short option_len = nptohs(rdata + 2); 45 | if (only_option_code == 0 || only_option_code == option_code) { 46 | *flag = 1; 47 | if (verbose) 48 | fprintf(stderr, "Found EDNS option %hu of %hu bytes\n", option_code, option_len); 49 | } 50 | rdata_len -= 4; 51 | rdata += 4; 52 | if (option_len > rdata_len) 53 | goto done; 54 | rdata_len -= option_len; 55 | rdata += option_len; 56 | } 57 | 58 | done: 59 | ldns_pkt_free(pkt); 60 | return 0; 61 | } 62 | 63 | int 64 | main(int argc, char *argv[]) 65 | { 66 | pcap_t *in = NULL; 67 | struct pcap_pkthdr hdr; 68 | const u_char *data; 69 | pcap_dumper_t *out = NULL; 70 | int flag; 71 | 72 | progname = strdup(argv[0]); 73 | 74 | while ((flag = getopt(argc, argv, "o:v")) != -1) { 75 | switch (flag) { 76 | case 'o': 77 | only_option_code = strtoul(optarg, 0, 0); 78 | break; 79 | case 'v': 80 | verbose++; 81 | break; 82 | } 83 | } 84 | argc -= optind; 85 | argv += optind; 86 | 87 | in = my_pcap_open_offline("-"); 88 | out = pcap_dump_open(in, "-"); 89 | if (NULL == out) 90 | errx(1, "pcap_dump_open stdout"); 91 | pcap_layers_init(pcap_datalink(in), 0); 92 | callback_l7 = my_dns_handler; 93 | while ((data = pcap_next(in, &hdr))) { 94 | flag = 0; 95 | handle_pcap((u_char *) & flag, &hdr, data); 96 | if (flag) 97 | pcap_dump((void *) out, &hdr, data); 98 | } 99 | pcap_close(in); 100 | pcap_dump_close(out); 101 | exit(0); 102 | } 103 | -------------------------------------------------------------------------------- /pcap-extract-interval.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static void 12 | usage(void) 13 | { 14 | fprintf(stderr, "usage: pcap-extract-interval [-x] begin end\n"); 15 | fprintf(stderr, "\tbegin\tUnix timestamp\n"); 16 | fprintf(stderr, "\tend\tUnix timestamp\n"); 17 | fprintf(stderr, "\t-x\texit at first timestamp after end time\n"); 18 | exit(1); 19 | } 20 | 21 | int 22 | main(int argc, char *argv[]) 23 | { 24 | pcap_t *in = NULL; 25 | pcap_dumper_t *out = NULL; 26 | char errbuf[PCAP_ERRBUF_SIZE + 1]; 27 | struct pcap_pkthdr hdr; 28 | const u_char *data; 29 | time_t beg; 30 | time_t end; 31 | int ch; 32 | int opt_exit = 0; 33 | 34 | while ((ch = getopt(argc, argv, "x")) != -1) { 35 | switch (ch) { 36 | case 'x': 37 | opt_exit = 1; 38 | break; 39 | case '?': 40 | case 'h': 41 | default: 42 | usage(); 43 | break; 44 | } 45 | } 46 | 47 | 48 | if ((argc - optind) < 2) { 49 | usage(); 50 | } 51 | beg = atoi(argv[optind]); 52 | end = atoi(argv[optind+1]); 53 | 54 | in = pcap_open_offline("-", errbuf); 55 | if (NULL == in) { 56 | fprintf(stderr, "stdin: %s", errbuf); 57 | exit(1); 58 | } 59 | out = pcap_dump_open(in, "-"); 60 | if (NULL == out) { 61 | perror("stdout"); 62 | exit(1); 63 | } 64 | while ((data = pcap_next(in, &hdr))) { 65 | if (hdr.ts.tv_sec < beg) 66 | continue; 67 | if (hdr.ts.tv_sec >= end) { 68 | if (opt_exit) { 69 | exit(0); 70 | } else { 71 | continue; 72 | } 73 | } 74 | pcap_dump((void *) out, &hdr, data); 75 | } 76 | pcap_close(in); 77 | pcap_dump_close(out); 78 | exit(0); 79 | } 80 | -------------------------------------------------------------------------------- /pcap-find-misordered.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define XCMP(X,Y) (XY?1:0)) 17 | 18 | int ARRAYSZ = 1 << 20; 19 | struct timeval *tvals = NULL; 20 | int count; 21 | int misordered = 0; 22 | 23 | int 24 | tv_cmp(struct timeval *a, struct timeval *b) 25 | { 26 | return (a->tv_sec == b->tv_sec) ? XCMP(a->tv_usec, b->tv_usec) : XCMP(a->tv_sec, b->tv_sec); 27 | } 28 | 29 | void 30 | flush(int keep) 31 | { 32 | if (keep) 33 | memmove(tvals, tvals + count - keep, keep * sizeof(*tvals)); 34 | count = keep; 35 | } 36 | 37 | void 38 | push(struct pcap_pkthdr *hdr, const u_char * data) 39 | { 40 | assert(count < ARRAYSZ); 41 | *(tvals + count) = hdr->ts; 42 | count++; 43 | if (count < 2) 44 | return; 45 | if (0 > tv_cmp(tvals + count - 1, tvals + count - 2)) { 46 | printf("timestamp went from %10lld.%06ld to %10lld.%06ld\n", 47 | (long long int) (tvals + count - 2)->tv_sec, 48 | (tvals + count - 2)->tv_usec, (long long int) (tvals + count - 1)->tv_sec, (tvals + count - 1)->tv_usec); 49 | misordered++; 50 | } 51 | } 52 | 53 | int 54 | main(int argc, char *argv[]) 55 | { 56 | pcap_t *in = NULL; 57 | char errbuf[PCAP_ERRBUF_SIZE + 1]; 58 | struct pcap_pkthdr hdr; 59 | const u_char *data; 60 | 61 | 62 | if (argc < 2) { 63 | fprintf(stderr, "usage: pcap-reorder sortsize\n"); 64 | exit(1); 65 | } 66 | ARRAYSZ = atoi(argv[1]); 67 | if (ARRAYSZ < 2) { 68 | fprintf(stderr, "sortsize should be greater than 1\n"); 69 | exit(1); 70 | } 71 | tvals = calloc(ARRAYSZ, sizeof(*tvals)); 72 | 73 | in = pcap_open_offline("-", errbuf); 74 | if (NULL == in) { 75 | fprintf(stderr, "stdin: %s", errbuf); 76 | exit(1); 77 | } 78 | while ((data = pcap_next(in, &hdr))) { 79 | push(&hdr, data); 80 | if (ARRAYSZ == count) 81 | flush(3 * count / 4); 82 | } 83 | pcap_close(in); 84 | exit(0 == misordered ? 0 : 1); 85 | } 86 | -------------------------------------------------------------------------------- /pcap-fix-linux-af-inet6.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "pcap-tools.h" 13 | 14 | char *progname = NULL; 15 | 16 | int 17 | needs_fixing(const struct pcap_pkthdr *hdr, const u_char * data) 18 | { 19 | unsigned int family; 20 | if (hdr->caplen < 4) 21 | return 0; 22 | family = nptohl(data); 23 | if (10 == family) 24 | return 1; 25 | return 0; 26 | } 27 | 28 | void 29 | fix(const u_char * data) 30 | { 31 | unsigned int family = htonl(28); 32 | memcpy((void *) data, &family, sizeof(family)); 33 | } 34 | 35 | void 36 | usage(void) 37 | { 38 | fprintf(stderr, "usage: %s pcapfiles ...\n", progname); 39 | exit(1); 40 | } 41 | 42 | int 43 | main(int argc, char *argv[]) 44 | { 45 | pcap_t *in = NULL; 46 | pcap_dumper_t *out = NULL; 47 | struct pcap_pkthdr hdr; 48 | const u_char *data; 49 | int i; 50 | int nfixed = 0; 51 | int dryrun = 0; 52 | int dlt = 0; 53 | 54 | progname = argv[0]; 55 | while ((i = getopt(argc, argv, "n")) != -1) { 56 | switch (i) { 57 | case 'n': 58 | dryrun = 1; 59 | break; 60 | case '?': 61 | default: 62 | usage(); 63 | } 64 | } 65 | argc -= optind; 66 | argv += optind; 67 | 68 | 69 | if (argc < 1) 70 | usage(); 71 | for (i = 0; i < argc; i++) { 72 | in = my_pcap_open_offline(argv[i]); 73 | dlt = pcap_datalink(in); 74 | while ((data = pcap_next(in, &hdr))) { 75 | if (DLT_LOOP == dlt && needs_fixing(&hdr, data)) { 76 | nfixed++; 77 | if (dryrun) 78 | warnx("found bad packet of at %10lld.%06lld", 79 | (long long int) hdr.ts.tv_sec, (long long int) hdr.ts.tv_usec); 80 | else 81 | fix(data); 82 | } 83 | if (!out) { 84 | out = pcap_dump_open(in, "-"); 85 | if (NULL == out) { 86 | perror("stdout"); 87 | exit(1); 88 | } 89 | } 90 | pcap_dump((void *) out, &hdr, data); 91 | } 92 | my_pcap_close_offline(in); 93 | } 94 | if (out) 95 | pcap_dump_close(out); 96 | fprintf(stderr, "%s: Fixed %d bad packets\n", progname, nfixed); 97 | exit(0); 98 | } 99 | 100 | int 101 | is_bogus(struct pcap_pkthdr *thishdr, const u_char * thisdata) 102 | { 103 | if (thishdr->caplen > 65535) 104 | return 1; 105 | if (thishdr->len > 65535) 106 | return 1; 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /pcap-join.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "pcap-tools.h" 19 | 20 | pcap_dumper_t *out = NULL; 21 | const char *filterstr = 0; 22 | int opt_mergecap = 0; 23 | const char *progname = 0; 24 | const char *mergecap_cmd = "|mergecap -w -"; 25 | 26 | typedef struct 27 | { 28 | unsigned int size; 29 | unsigned int cnt; 30 | char **files; 31 | } filelist; 32 | 33 | int verbose = 0; 34 | 35 | void 36 | join(const char *pcapfile) 37 | { 38 | pcap_t *in = NULL; 39 | struct pcap_pkthdr hdr; 40 | const u_char *data; 41 | if (verbose > 0) 42 | fprintf(stderr, "Joining %s\n", pcapfile); 43 | in = my_pcap_open_offline(pcapfile); 44 | if (filterstr) { 45 | struct bpf_program fp; 46 | memset(&fp, '\0', sizeof(fp)); 47 | if (pcap_compile(in, &fp, filterstr, 1, 0) < 0) { 48 | fprintf(stderr, "pcap_compile failed: %s\n", pcap_geterr(in)); 49 | exit(1); 50 | } 51 | if (pcap_setfilter(in, &fp) < 0) { 52 | fprintf(stderr, "pcap_setfilter failed: %s\n", pcap_geterr(in)); 53 | exit(1); 54 | } 55 | } 56 | while ((data = pcap_next(in, &hdr))) { 57 | if (!out) { 58 | out = pcap_dump_open(in, "-"); 59 | if (NULL == out) { 60 | perror("stdout"); 61 | exit(1); 62 | } 63 | } 64 | pcap_dump((void *) out, &hdr, data); 65 | } 66 | my_pcap_close_offline(in); 67 | } 68 | 69 | struct 70 | { 71 | int nmatch; 72 | const char *pat; 73 | const char *fmt; 74 | regex_t *re; 75 | } time_patterns[] = { 76 | {7, "([0-9]{4})([0-9]{2})([0-9]{2}).([0-9]{2}):([0-9]{2}):([0-9]{2})", "%Y%m%d.%H:%M:%S", 0}, 77 | {7, "([0-9]{4})([0-9]{2})([0-9]{2})/([0-9]{2})([0-9]{2})([0-9]{2})", "%Y%m%d/%H%M%S", 0}, 78 | {0, 0, 0, 0} 79 | }; 80 | 81 | time_t 82 | parse_timestamp(const char *s) 83 | { 84 | regmatch_t pmatch[10]; 85 | struct tm tm; 86 | unsigned int k; 87 | for (k = 0; time_patterns[k].pat; k++) { 88 | if (0 == time_patterns[k].re) { 89 | time_patterns[k].re = calloc(1, sizeof(*time_patterns[k].re)); 90 | if (0 != regcomp(time_patterns[k].re, time_patterns[k].pat, REG_EXTENDED)) { 91 | fprintf(stderr, "regcomp '%s' failed\n", time_patterns[k].pat); 92 | exit(1); 93 | } 94 | } 95 | if (0 != regexec(time_patterns[k].re, s, time_patterns[k].nmatch, pmatch, 0)) { 96 | continue; 97 | } 98 | assert(pmatch[0].rm_so > -1); 99 | if (0 == strptime(s + pmatch[0].rm_so, time_patterns[k].fmt, &tm)) 100 | continue; 101 | return timegm(&tm); 102 | } 103 | fprintf(stderr, "no time patterns matched '%s'\n", s); 104 | return 0; 105 | } 106 | 107 | int 108 | qsort_strcmp(const void *a, const void *b) 109 | { 110 | return strcmp(*((char **) a), *((char **) b)); 111 | } 112 | 113 | int 114 | qsort_strptime(const void *a, const void *b) 115 | { 116 | time_t time_a = parse_timestamp(*((char **) a)); 117 | time_t time_b = parse_timestamp(*((char **) b)); 118 | if (time_a < time_b) 119 | return -1; 120 | if (time_a > time_b) 121 | return 1; 122 | return -1; 123 | } 124 | 125 | void 126 | usage(void) 127 | { 128 | fprintf(stderr, "usage: pcap-join [options] pcapfiles ...\n"); 129 | fprintf(stderr, " pcap-join [options] directory\n"); 130 | fprintf(stderr, " pcap-join [options] (reads files from stdin)\n"); 131 | fprintf(stderr, "options:\n"); 132 | fprintf(stderr, " -v verbose\n"); 133 | fprintf(stderr, " -b filter apply pcap filter\n"); 134 | exit(1); 135 | } 136 | 137 | filelist * 138 | filelist_init(void) 139 | { 140 | filelist *fl; 141 | fl = calloc(1, sizeof(*fl)); 142 | fl->size = 64; 143 | fl->cnt = 0; 144 | fl->files = calloc(fl->size, sizeof(char *)); 145 | return fl; 146 | } 147 | 148 | void 149 | filelist_add(filelist * fl, const char *file) 150 | { 151 | if (fl->cnt == fl->size) { 152 | char **tmp = calloc(fl->size << 1, sizeof(char *)); 153 | memcpy(tmp, fl->files, fl->size * sizeof(char *)); 154 | free(fl->files); 155 | fl->files = tmp; 156 | fl->size <<= 1; 157 | } 158 | fl->files[fl->cnt++] = strdup(file); 159 | } 160 | 161 | int 162 | main(int argc, char *argv[]) 163 | { 164 | int i; 165 | filelist *infiles = 0; 166 | if (strrchr(argv[0], '/')) 167 | progname = strdup(1 + strrchr(argv[0], '/')); 168 | else 169 | progname = strdup(argv[0]); 170 | while ((i = getopt(argc, argv, "b:c:hmv")) != -1) { 171 | switch (i) { 172 | case 'b': 173 | filterstr = strdup(optarg); 174 | break; 175 | case 'c': /* used as comment, eg in ps output */ 176 | break; 177 | case '?': 178 | case 'h': 179 | default: 180 | usage(); 181 | break; 182 | case 'm': 183 | opt_mergecap = 1; 184 | break; 185 | case 'v': 186 | verbose++; 187 | break; 188 | } 189 | } 190 | argc -= optind; 191 | argv += optind; 192 | 193 | infiles = filelist_init(); 194 | 195 | if (0 == argc) { 196 | char buf[512]; 197 | /* read file names from stdin */ 198 | while (NULL != fgets(buf, 512, stdin)) { 199 | strtok(buf, "\r\n"); 200 | filelist_add(infiles, buf); 201 | } 202 | } else 203 | for (i = 0; i < argc; i++) { 204 | struct stat sb; 205 | if (stat(argv[i], &sb) < 0) 206 | err(1, "%s", argv[i]); 207 | if (S_ISDIR(sb.st_mode)) { 208 | DIR *d; 209 | struct dirent *e; 210 | /* 211 | * read unsorted files 212 | */ 213 | d = opendir(argv[i]); 214 | if (NULL == d) 215 | err(1, "%s", argv[i]); 216 | while (NULL != (e = readdir(d))) { 217 | char path[512]; 218 | if (*e->d_name == '.') 219 | continue; 220 | snprintf(path, sizeof(path), "%s/%s", argv[i], e->d_name); 221 | filelist_add(infiles, path); 222 | } 223 | closedir(d); 224 | qsort(infiles->files, infiles->cnt, sizeof(char *), qsort_strcmp); 225 | 226 | } else { 227 | filelist_add(infiles, argv[i]); 228 | } 229 | } 230 | 231 | if (opt_mergecap) { 232 | size_t bufsize = 0; 233 | unsigned int j = 0; 234 | unsigned int k = 0; 235 | filelist *new = 0; 236 | new = filelist_init(); 237 | qsort(infiles->files, infiles->cnt, sizeof(char *), qsort_strptime); 238 | while (j < infiles->cnt) { 239 | char *buf = 0; 240 | unsigned int i; 241 | bufsize = strlen(mergecap_cmd); 242 | while (k < infiles->cnt && parse_timestamp(infiles->files[j]) == parse_timestamp(infiles->files[k])) { 243 | bufsize += 1 + strlen(infiles->files[k]); 244 | k++; 245 | } 246 | bufsize += 1; /* terminating null */ 247 | buf = calloc(bufsize, sizeof(char *)); 248 | strcat(buf, mergecap_cmd); 249 | for (i = j; i < k; i++) { 250 | strcat(buf, " "); 251 | strcat(buf, infiles->files[i]); 252 | } 253 | assert(strlen(buf) == bufsize - 1); 254 | filelist_add(new, buf); 255 | j = k; 256 | free(buf); 257 | buf = 0; 258 | } 259 | for (i = 0; i < infiles->cnt; i++) 260 | free(infiles->files[i]); 261 | free(infiles); 262 | infiles = new; 263 | } 264 | 265 | for (i = 0; i < infiles->cnt; i++) { 266 | join(infiles->files[i]); 267 | free(infiles->files[i]); 268 | } 269 | free(infiles); 270 | if (out) 271 | pcap_dump_close(out); 272 | exit(0); 273 | } 274 | -------------------------------------------------------------------------------- /pcap-merge-sorted-sip.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "pcap-tools.h" 22 | #include "pcap_layers.h" 23 | 24 | struct _in 25 | { 26 | pcap_t *pcap; 27 | struct pcap_pkthdr hdr; 28 | u_char data[65536]; 29 | struct sockaddr_storage ss; 30 | }; 31 | 32 | #define MAX_INPUTS 256 33 | static struct _in inputs[MAX_INPUTS]; 34 | static unsigned int n_inputs = 0; 35 | static uint64_t v4count = 0; 36 | static uint64_t v6count = 0; 37 | 38 | 39 | int 40 | my_ip4_handler(const struct ip *ip4, int len, void *userdata) 41 | { 42 | struct _in *in = userdata; 43 | struct sockaddr_in *s = (struct sockaddr_in *) &in->ss; 44 | s->sin_family = AF_INET; 45 | s->sin_addr = ip4->ip_src; 46 | v4count++; 47 | return 0; 48 | } 49 | 50 | int 51 | my_ip6_handler(const struct ip6_hdr *ip6, int len, void *userdata) 52 | { 53 | struct _in *in = userdata; 54 | struct sockaddr_in6 *s = (struct sockaddr_in6 *) &in->ss; 55 | s->sin6_family = AF_INET6; 56 | s->sin6_addr = ip6->ip6_src; 57 | v6count++; 58 | return 0; 59 | } 60 | 61 | pcap_dumper_t * 62 | my_pcap_dump_open(pcap_t * other, const char *f) 63 | { 64 | pcap_dumper_t *out; 65 | out = pcap_dump_open(other, f); 66 | if (NULL == out) 67 | errx(1, "%s", f); 68 | return out; 69 | } 70 | 71 | void 72 | read_next_packet(struct _in *in) 73 | { 74 | const u_char *data; 75 | data = pcap_next(in->pcap, &in->hdr); 76 | if (0 == data) { 77 | my_pcap_close_offline(in->pcap); 78 | in->pcap = 0; 79 | return; 80 | } 81 | memcpy(&in->data[0], data, in->hdr.caplen); 82 | handle_pcap((void *) in, &in->hdr, in->data); 83 | } 84 | 85 | struct _in * 86 | compare(struct _in *this, struct _in *that) 87 | { 88 | int r; 89 | assert(that); 90 | if (0 == this) 91 | return that; 92 | if (this->ss.ss_family < that->ss.ss_family) 93 | return this; 94 | if (this->ss.ss_family > that->ss.ss_family) 95 | return that; 96 | if (AF_INET == this->ss.ss_family) { 97 | struct sockaddr_in *sa_this = (struct sockaddr_in *) &this->ss; 98 | struct sockaddr_in *sa_that = (struct sockaddr_in *) &that->ss; 99 | r = memcmp(&sa_this->sin_addr, &sa_that->sin_addr, 4); 100 | if (r < 0) 101 | return this; 102 | else if (r > 0) 103 | return that; 104 | } 105 | if (AF_INET6 == this->ss.ss_family) { 106 | struct sockaddr_in6 *sa_this = (struct sockaddr_in6 *) &this->ss; 107 | struct sockaddr_in6 *sa_that = (struct sockaddr_in6 *) &that->ss; 108 | r = memcmp(&sa_this->sin6_addr, &sa_that->sin6_addr, 16); 109 | if (r < 0) 110 | return this; 111 | else if (r > 0) 112 | return that; 113 | } 114 | return this; 115 | } 116 | 117 | void 118 | pcap_merge_sorted_sip(int argc, char *argv[], const char *outf) 119 | { 120 | pcap_dumper_t *out = NULL; 121 | struct timeval start; 122 | struct timeval stop; 123 | struct timeval duration; 124 | unsigned int i; 125 | 126 | gettimeofday(&start, NULL); 127 | for (i = 0; i < argc; i++) { 128 | struct _in *in = &inputs[n_inputs++]; 129 | memset(in, 0, sizeof(*in)); 130 | in->pcap = my_pcap_open_offline(argv[i]); 131 | if (0 == i) { 132 | pcap_layers_init(pcap_datalink(in->pcap), 0); 133 | callback_ipv4 = my_ip4_handler; 134 | callback_ipv6 = my_ip6_handler; 135 | } else if (pcap_datalink(inputs[0].pcap) != pcap_datalink(in->pcap)) { 136 | errx(1, "All pcap input files must have same datalink type"); 137 | } 138 | read_next_packet(in); 139 | } 140 | 141 | out = my_pcap_dump_open(inputs[0].pcap, outf); 142 | 143 | for (;;) { 144 | struct _in *best = 0; 145 | for (i = 0; i < n_inputs; i++) { 146 | struct _in *in = &inputs[i]; 147 | if (0 == in->pcap) 148 | continue; 149 | best = compare(best, in); 150 | } 151 | if (0 == best) 152 | break; 153 | pcap_dump((u_char *) out, &best->hdr, best->data); 154 | read_next_packet(best); 155 | } 156 | 157 | pcap_dump_close(out); 158 | gettimeofday(&stop, NULL); 159 | timersub(&stop, &start, &duration); 160 | fprintf(stderr, "\nSorted %" PRIu64 " IPv4 and %" PRIu64 " IPv6 packets in %d.%d seconds\n", 161 | v4count, v6count, (int) duration.tv_sec, (int) duration.tv_usec / 100000); 162 | } 163 | 164 | int 165 | main(int argc, char *argv[]) 166 | { 167 | if (argc < 2) { 168 | fprintf(stderr, "usage: pcap-merge-sorted-sip in1 in2 ... > out\n"); 169 | exit(1); 170 | } 171 | argc--; 172 | argv++; 173 | pcap_merge_sorted_sip(argc, argv, "-"); 174 | exit(0); 175 | } 176 | -------------------------------------------------------------------------------- /pcap-print-sip-protocol.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include "pcap_layers.h" 23 | 24 | #ifdef __GLIBC__ 25 | #define __u6_addr __in6_u 26 | #endif 27 | 28 | 29 | struct inx_addr 30 | { 31 | uint8_t family; 32 | union 33 | { 34 | struct in_addr in4; 35 | struct in6_addr in6; 36 | } u; 37 | }; 38 | 39 | struct state 40 | { 41 | struct inx_addr a; 42 | int proto; 43 | }; 44 | 45 | 46 | static pcap_t *in = NULL; 47 | 48 | int 49 | my_udp_handler(const struct udphdr *udp, int len, void *userdata) 50 | { 51 | struct state *s = userdata; 52 | s->proto = 17; 53 | return 0; 54 | } 55 | 56 | int 57 | my_tcp_handler(const struct tcphdr *tcp, int len, void *userdata) 58 | { 59 | struct state *s = userdata; 60 | s->proto = 6; 61 | return 0; 62 | } 63 | 64 | 65 | int 66 | my_ip4_handler(const struct ip *ip4, int len, void *userdata) 67 | { 68 | struct state *s = userdata; 69 | s->a.family = AF_INET; 70 | s->a.u.in4 = ip4->ip_src; 71 | return 0; 72 | } 73 | 74 | int 75 | my_ip6_handler(const struct ip6_hdr *ip6, int len, void *userdata) 76 | { 77 | struct state *s = userdata; 78 | s->a.family = AF_INET6; 79 | s->a.u.in6 = ip6->ip6_src; 80 | return 0; 81 | } 82 | 83 | int 84 | is_rfc1918(struct inx_addr a) 85 | { 86 | unsigned long clt_addr = ntohl(a.u.in4.s_addr); 87 | if (AF_INET != a.family) 88 | return 0; 89 | // 10/8 90 | if ((clt_addr & 0xff000000) == 0x0A000000) 91 | return 1; 92 | // 172.16/12 93 | if ((clt_addr & 0xfff00000) == 0xAC100000) 94 | return 1; 95 | // 192.168/16 96 | if ((clt_addr & 0xffff0000) == 0xC0A80000) 97 | return 1; 98 | 99 | return 0; 100 | } 101 | 102 | 103 | int 104 | main(int argc, char *argv[]) 105 | { 106 | char errbuf[PCAP_ERRBUF_SIZE + 1]; 107 | struct pcap_pkthdr hdr; 108 | const u_char *data; 109 | 110 | setbuf(stdout, NULL); 111 | setbuf(stderr, NULL); 112 | 113 | in = pcap_open_offline("-", errbuf); 114 | if (NULL == in) { 115 | fprintf(stderr, "stdin: %s", errbuf); 116 | exit(1); 117 | } 118 | 119 | pcap_layers_init(pcap_datalink(in), 0); 120 | callback_ipv4 = my_ip4_handler; 121 | callback_ipv6 = my_ip6_handler; 122 | callback_udp = my_udp_handler; 123 | callback_tcp = my_tcp_handler; 124 | 125 | while ((data = pcap_next(in, &hdr))) { 126 | char buf[128]; 127 | struct state s; 128 | memset(&s, 0, sizeof(s)); 129 | handle_pcap((u_char *) & s, &hdr, data); 130 | if (s.a.family == 0) 131 | continue; 132 | inet_ntop(s.a.family, &s.a.u, buf, sizeof(buf)); 133 | if (s.proto) 134 | printf("%s %d\n", buf, s.proto); 135 | } 136 | return 0; 137 | } 138 | -------------------------------------------------------------------------------- /pcap-print-sip.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include "pcap_layers.h" 23 | 24 | #ifdef __GLIBC__ 25 | #define __u6_addr __in6_u 26 | #endif 27 | 28 | 29 | struct inx_addr 30 | { 31 | uint8_t family; 32 | union 33 | { 34 | struct in_addr in4; 35 | struct in6_addr in6; 36 | } u; 37 | }; 38 | 39 | static pcap_t *in = NULL; 40 | 41 | 42 | int 43 | my_ip4_handler(const struct ip *ip4, int len, void *userdata) 44 | { 45 | struct inx_addr *a = userdata; 46 | a->family = AF_INET; 47 | a->u.in4 = ip4->ip_src; 48 | return 0; 49 | } 50 | 51 | int 52 | my_ip6_handler(const struct ip6_hdr *ip6, int len, void *userdata) 53 | { 54 | struct inx_addr *a = userdata; 55 | a->family = AF_INET6; 56 | a->u.in6 = ip6->ip6_src; 57 | return 0; 58 | } 59 | 60 | int 61 | is_rfc1918(struct inx_addr a) 62 | { 63 | unsigned long clt_addr = ntohl(a.u.in4.s_addr); 64 | if (AF_INET != a.family) 65 | return 0; 66 | // 10/8 67 | if ((clt_addr & 0xff000000) == 0x0A000000) 68 | return 1; 69 | // 172.16/12 70 | if ((clt_addr & 0xfff00000) == 0xAC100000) 71 | return 1; 72 | // 192.168/16 73 | if ((clt_addr & 0xffff0000) == 0xC0A80000) 74 | return 1; 75 | 76 | return 0; 77 | } 78 | 79 | 80 | int 81 | main(int argc, char *argv[]) 82 | { 83 | char errbuf[PCAP_ERRBUF_SIZE + 1]; 84 | struct pcap_pkthdr hdr; 85 | const u_char *data; 86 | 87 | setbuf(stdout, NULL); 88 | setbuf(stderr, NULL); 89 | 90 | in = pcap_open_offline("-", errbuf); 91 | if (NULL == in) { 92 | fprintf(stderr, "stdin: %s", errbuf); 93 | exit(1); 94 | } 95 | 96 | pcap_layers_init(pcap_datalink(in), 0); 97 | callback_ipv4 = my_ip4_handler; 98 | callback_ipv6 = my_ip6_handler; 99 | 100 | while ((data = pcap_next(in, &hdr))) { 101 | char buf[128]; 102 | struct inx_addr src; 103 | memset(&src, 0, sizeof(src)); 104 | handle_pcap((u_char *) & src, &hdr, data); 105 | if (src.family == 0) 106 | continue; 107 | inet_ntop(src.family, &src.u, buf, sizeof(buf)); 108 | puts(buf); 109 | } 110 | return 0; 111 | } 112 | -------------------------------------------------------------------------------- /pcap-print-tcp-options.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include "pcap_layers.h" 23 | 24 | #ifdef __GLIBC__ 25 | #define __u6_addr __in6_u 26 | #endif 27 | 28 | 29 | struct inx_addr 30 | { 31 | uint8_t family; 32 | union 33 | { 34 | struct in_addr in4; 35 | struct in6_addr in6; 36 | } u; 37 | }; 38 | 39 | struct state 40 | { 41 | struct inx_addr src; 42 | struct inx_addr dst; 43 | }; 44 | 45 | 46 | static pcap_t *in = NULL; 47 | 48 | int 49 | my_tcp_handler(const struct tcphdr *tcp, int len, void *userdata) 50 | { 51 | struct state *s = userdata; 52 | char sbuf[128]; 53 | char dbuf[128]; 54 | unsigned int doff; 55 | char sep = '\t'; 56 | inet_ntop(s->src.family, &s->src.u, sbuf, sizeof(sbuf)); 57 | inet_ntop(s->dst.family, &s->dst.u, dbuf, sizeof(dbuf)); 58 | printf("%-30s %-30s %c%c%c%c%c%c", sbuf, dbuf, 59 | #ifdef TH_FIN 60 | /* BSD */ 61 | tcp->th_flags & TH_URG ? 'U' : '.', 62 | tcp->th_flags & TH_ACK ? 'A' : '.', 63 | tcp->th_flags & TH_PUSH ? 'P' : '.', 64 | tcp->th_flags & TH_RST ? 'R' : '.', tcp->th_flags & TH_SYN ? 'S' : '.', tcp->th_flags & TH_FIN ? 'F' : '.' 65 | #else 66 | /* Linux */ 67 | tcp->urg ? 'U' : '.', 68 | tcp->ack ? 'A' : '.', tcp->psh ? 'P' : '.', tcp->rst ? 'R' : '.', tcp->syn ? 'S' : '.', tcp->fin ? 'F' : '.' 69 | #endif 70 | ); 71 | #ifdef TH_FIN 72 | /* BSD */ 73 | doff = tcp->th_off << 2; 74 | #else 75 | /* Linux */ 76 | doff = tcp->doff << 2; 77 | #endif 78 | if (doff > sizeof(*tcp)) { 79 | unsigned int hdrlen = doff - sizeof(*tcp); 80 | uint8_t *x = (uint8_t *) (tcp + 1); 81 | uint8_t optlen; 82 | while (hdrlen > 0) { 83 | uint8_t opt = *x; 84 | printf("%copt%u", sep, opt); 85 | if (0 == opt || 1 == opt) { 86 | optlen = 1; 87 | } else { 88 | if (hdrlen < 2) 89 | break; 90 | optlen = *(x + 1); 91 | if (optlen < 2 || optlen > hdrlen) 92 | break; 93 | } 94 | x += optlen; 95 | hdrlen -= optlen; 96 | sep = ','; 97 | } 98 | } 99 | printf("\n"); 100 | return 0; 101 | } 102 | 103 | 104 | int 105 | my_ip4_handler(const struct ip *ip4, int len, void *userdata) 106 | { 107 | struct state *s = userdata; 108 | s->src.family = AF_INET; 109 | s->src.u.in4 = ip4->ip_src; 110 | s->dst.family = AF_INET; 111 | s->dst.u.in4 = ip4->ip_dst; 112 | return 0; 113 | } 114 | 115 | int 116 | my_ip6_handler(const struct ip6_hdr *ip6, int len, void *userdata) 117 | { 118 | struct state *s = userdata; 119 | s->src.family = AF_INET6; 120 | s->src.u.in6 = ip6->ip6_src; 121 | s->dst.family = AF_INET6; 122 | s->dst.u.in6 = ip6->ip6_dst; 123 | return 0; 124 | } 125 | 126 | int 127 | main(int argc, char *argv[]) 128 | { 129 | char errbuf[PCAP_ERRBUF_SIZE + 1]; 130 | struct pcap_pkthdr hdr; 131 | const u_char *data; 132 | 133 | setbuf(stdout, NULL); 134 | setbuf(stderr, NULL); 135 | 136 | in = pcap_open_offline("-", errbuf); 137 | if (NULL == in) { 138 | fprintf(stderr, "stdin: %s", errbuf); 139 | exit(1); 140 | } 141 | 142 | pcap_layers_init(pcap_datalink(in), 0); 143 | callback_ipv4 = my_ip4_handler; 144 | callback_ipv6 = my_ip6_handler; 145 | callback_tcp = my_tcp_handler; 146 | 147 | while ((data = pcap_next(in, &hdr))) { 148 | struct state s; 149 | memset(&s, 0, sizeof(s)); 150 | handle_pcap((u_char *) & s, &hdr, data); 151 | 152 | } 153 | return 0; 154 | } 155 | -------------------------------------------------------------------------------- /pcap-print-time-qname-qtype-rcode.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include "pcap_layers.h" 25 | 26 | #ifdef __GLIBC__ 27 | #define __u6_addr __in6_u 28 | #endif 29 | 30 | 31 | static pcap_t *in = NULL; 32 | static struct pcap_pkthdr hdr; 33 | static int include_queries = 0; 34 | 35 | int 36 | my_dns_handler(const u_char * buf, int len, void *userdata) 37 | { 38 | ldns_pkt *pkt = 0; 39 | ldns_rr_list *qd = 0; 40 | ldns_rr *q = 0; 41 | ldns_rdf *qn = 0; 42 | ldns_rr_type qt; 43 | char *qn_str = 0; 44 | if (LDNS_STATUS_OK != ldns_wire2pkt(&pkt, buf, len)) 45 | goto done; 46 | if (1 != ldns_pkt_qr(pkt) && !include_queries) 47 | goto done; 48 | qd = ldns_pkt_question(pkt); 49 | if (0 == qd) 50 | goto done; 51 | q = ldns_rr_list_rr(qd, 0); 52 | if (0 == q) 53 | goto done; 54 | qn = ldns_rr_owner(q); 55 | if (0 == qn) 56 | goto done; 57 | qn_str = ldns_rdf2str(qn); 58 | qt = ldns_rr_get_type(q); 59 | printf("%10lu.%06lu %s %d %d\n", hdr.ts.tv_sec, hdr.ts.tv_usec, qn_str, qt, ldns_pkt_get_rcode(pkt)); 60 | done: 61 | ldns_pkt_free(pkt); 62 | LDNS_FREE(qn_str); 63 | return 0; 64 | } 65 | 66 | 67 | int 68 | main(int argc, char *argv[]) 69 | { 70 | char errbuf[PCAP_ERRBUF_SIZE + 1]; 71 | const u_char *data; 72 | int i; 73 | 74 | while ((i = getopt(argc, argv, "q")) != -1) { 75 | switch (i) { 76 | case 'q': 77 | include_queries = 1; 78 | break; 79 | case '?': 80 | default: 81 | fprintf(stderr, "usage: %s [-q] < pcap-in\n", argv[0]); 82 | exit(1); 83 | } 84 | } 85 | argc -= optind; 86 | argv += optind; 87 | 88 | setbuf(stdout, NULL); 89 | setbuf(stderr, NULL); 90 | 91 | in = pcap_open_offline("-", errbuf); 92 | if (NULL == in) { 93 | fprintf(stderr, "stdin: %s", errbuf); 94 | exit(1); 95 | } 96 | 97 | pcap_layers_init(pcap_datalink(in), 0); 98 | callback_l7 = my_dns_handler; 99 | 100 | while ((data = pcap_next(in, &hdr))) { 101 | handle_pcap(0, &hdr, data); 102 | } 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /pcap-remove-bogus.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "pcap-tools.h" 12 | 13 | /* 14 | * Remove duplicated packets from a pcap file 15 | */ 16 | 17 | char *progname = NULL; 18 | int is_bogus(struct pcap_pkthdr *thishdr, const u_char * thisdata); 19 | 20 | void 21 | usage(void) 22 | { 23 | fprintf(stderr, "usage: %s pcapfiles ...\n", progname); 24 | exit(1); 25 | } 26 | 27 | int 28 | main(int argc, char *argv[]) 29 | { 30 | pcap_t *in = NULL; 31 | pcap_dumper_t *out = NULL; 32 | struct pcap_pkthdr hdr; 33 | const u_char *data; 34 | int i; 35 | int nbogus = 0; 36 | int dryrun = 0; 37 | 38 | progname = argv[0]; 39 | while ((i = getopt(argc, argv, "n")) != -1) { 40 | switch (i) { 41 | case 'n': 42 | dryrun = 1; 43 | break; 44 | case '?': 45 | default: 46 | usage(); 47 | } 48 | } 49 | argc -= optind; 50 | argv += optind; 51 | 52 | 53 | if (argc < 1) 54 | usage(); 55 | for (i = 0; i < argc; i++) { 56 | in = my_pcap_open_offline(argv[i]); 57 | while ((data = pcap_next(in, &hdr))) { 58 | if (is_bogus(&hdr, data)) { 59 | nbogus++; 60 | if (dryrun) 61 | warnx("found bogus packet of caplen=%d, len=%d, at %10lld.%06lld", 62 | hdr.caplen, hdr.len, (long long int) hdr.ts.tv_sec, (long long int) hdr.ts.tv_usec); 63 | else 64 | continue; 65 | } 66 | if (!out) { 67 | out = pcap_dump_open(in, "-"); 68 | if (NULL == out) { 69 | perror("stdout"); 70 | exit(1); 71 | } 72 | } 73 | pcap_dump((void *) out, &hdr, data); 74 | } 75 | my_pcap_close_offline(in); 76 | } 77 | if (out) 78 | pcap_dump_close(out); 79 | fprintf(stderr, "%s: Removed %d bad packets\n", progname, nbogus); 80 | exit(0); 81 | } 82 | 83 | int 84 | is_bogus(struct pcap_pkthdr *thishdr, const u_char * thisdata) 85 | { 86 | if (thishdr->caplen > 65535) 87 | return 1; 88 | if (thishdr->len > 65535) 89 | return 1; 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /pcap-remove-dupe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | #include "pcap-tools.h" 14 | 15 | #ifdef __GLIBC__ 16 | #include 17 | #define MD5Init MD5_Init 18 | #define MD5Update MD5_Update 19 | #define MD5Final MD5_Final 20 | #else 21 | #include 22 | #endif 23 | 24 | /* 25 | * Remove duplicated packets from a pcap file 26 | */ 27 | 28 | int is_dupe(struct pcap_pkthdr *thishdr, const u_char * thisdata); 29 | 30 | int 31 | main(int argc, char *argv[]) 32 | { 33 | pcap_t *in = NULL; 34 | pcap_dumper_t *out = NULL; 35 | struct pcap_pkthdr hdr; 36 | const u_char *data; 37 | int i; 38 | int ndupes = 0; 39 | 40 | if (argc < 2) { 41 | fprintf(stderr, "usage: pcap-remove-dupe pcapfiles ..."); 42 | exit(1); 43 | } 44 | for (i = 1; i < argc; i++) { 45 | in = my_pcap_open_offline(argv[i]); 46 | while ((data = pcap_next(in, &hdr))) { 47 | if (is_dupe(&hdr, data)) { 48 | ndupes++; 49 | continue; 50 | } 51 | if (!out) { 52 | out = pcap_dump_open(in, "-"); 53 | if (NULL == out) { 54 | perror("stdout"); 55 | exit(1); 56 | } 57 | } 58 | pcap_dump((void *) out, &hdr, data); 59 | } 60 | my_pcap_close_offline(in); 61 | } 62 | if (out) 63 | pcap_dump_close(out); 64 | fprintf(stderr, "Removed %d dupes\n", ndupes); 65 | exit(0); 66 | } 67 | 68 | int 69 | is_dupe(struct pcap_pkthdr *thishdr, const u_char * thisdata) 70 | { 71 | static struct pcap_pkthdr lasthdr; 72 | static char lastdata[4096]; 73 | MD5_CTX md5; 74 | static unsigned int thisdigest[4]; 75 | static unsigned int lastdigest[4]; 76 | int rc = 0; 77 | /* 78 | * sigh, must compute MD5 for every packet 79 | */ 80 | MD5Init(&md5); 81 | MD5Update(&md5, thisdata, thishdr->len); 82 | MD5Final((u_char *) thisdigest, &md5); 83 | if (thishdr->ts.tv_usec != lasthdr.ts.tv_usec) 84 | (void) 0; 85 | else if (thishdr->ts.tv_sec != lasthdr.ts.tv_sec) 86 | (void) 0; 87 | else if (thishdr->caplen != lasthdr.caplen) 88 | (void) 0; 89 | else if (thishdr->len != lasthdr.len) 90 | (void) 0; 91 | else { 92 | if (memcmp(thisdigest, lastdigest, 16) == 0) 93 | rc = 1; 94 | } 95 | memcpy(lastdigest, thisdigest, 16); 96 | lasthdr = *thishdr; 97 | memcpy(lastdata, thisdata, thishdr->len); 98 | 99 | return rc; 100 | } 101 | -------------------------------------------------------------------------------- /pcap-reorder.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "pcap_layers.h" 17 | 18 | #define XCMP(X,Y) (XY?1:0)) 19 | 20 | int SORTSIZE = 256; 21 | struct _pkt 22 | { 23 | struct pcap_pkthdr hdr; 24 | u_char *data; 25 | }; 26 | int npkts = 0; 27 | struct _pkt *packets; 28 | struct timeval max_flushed = { 0, 0 }; 29 | 30 | int sort_err_fatal = 0; 31 | 32 | int 33 | my_ip4_handler(const struct ip *ip4, int len, void *userdata) 34 | { 35 | memset(userdata, 0, 16); 36 | memcpy(userdata, &ip4->ip_src, 4); 37 | return 0; 38 | } 39 | 40 | int 41 | my_ip6_handler(const struct ip6_hdr *ip6, int len, void *userdata) 42 | { 43 | memcpy(userdata, &ip6->ip6_src, 16); 44 | return 0; 45 | } 46 | 47 | 48 | int 49 | cmp_timeval(struct timeval a, struct timeval b) 50 | { 51 | return (a.tv_sec == b.tv_sec) 52 | ? XCMP(a.tv_usec, b.tv_usec) 53 | : XCMP(a.tv_sec, b.tv_sec); 54 | } 55 | 56 | int 57 | sorter(const void *A, const void *B) 58 | { 59 | struct _pkt *a = (struct _pkt *) A; 60 | struct _pkt *b = (struct _pkt *) B; 61 | return cmp_timeval(a->hdr.ts, b->hdr.ts); 62 | } 63 | 64 | void 65 | flush(pcap_dumper_t * out, int keep) 66 | { 67 | int i; 68 | if (0 == npkts) 69 | return; 70 | qsort(packets, npkts, sizeof(struct _pkt), sorter); 71 | for (i = 0; i < (npkts - keep); i++) { 72 | pcap_dump((void *) out, &packets[i].hdr, packets[i].data); 73 | free(packets[i].data); 74 | } 75 | max_flushed = packets[i - 1].hdr.ts; 76 | if (keep) 77 | memmove(&packets[0], &packets[npkts - keep], keep * sizeof(struct _pkt)); 78 | npkts = keep; 79 | } 80 | 81 | void 82 | push(struct pcap_pkthdr *hdr, const u_char * data) 83 | { 84 | assert(npkts < SORTSIZE); 85 | packets[npkts].hdr = *hdr; 86 | packets[npkts].data = malloc(hdr->caplen); 87 | if (0 == packets[npkts].data) 88 | err(1, "malloc"); 89 | memcpy(packets[npkts].data, data, hdr->caplen); 90 | if (cmp_timeval(max_flushed, hdr->ts) > 0) { 91 | warnx("sortsize %d is not large enough " 92 | "to fully sort this file. " 93 | "flushed=%10lld.%06lld, this=%10lld.%06lld", 94 | SORTSIZE, 95 | (long long int) max_flushed.tv_sec, 96 | (long long int) max_flushed.tv_usec, (long long int) hdr->ts.tv_sec, (long long int) hdr->ts.tv_usec); 97 | if (sort_err_fatal) 98 | exit(1); 99 | } 100 | npkts++; 101 | } 102 | 103 | void 104 | usage(void) 105 | { 106 | fprintf(stderr, "usage: pcap-reorder [-s] sortsize\n"); 107 | fprintf(stderr, "\t-s\tinput is sorted by source IP\n"); 108 | exit(1); 109 | } 110 | 111 | int 112 | main(int argc, char *argv[]) 113 | { 114 | pcap_t *in = NULL; 115 | pcap_dumper_t *out = NULL; 116 | char errbuf[PCAP_ERRBUF_SIZE + 1]; 117 | struct pcap_pkthdr hdr; 118 | const u_char *data; 119 | int ch; 120 | int sip_sorted = 0; 121 | u_char this_sip[16]; 122 | u_char that_sip[16]; 123 | 124 | while ((ch = getopt(argc, argv, "sx")) != -1) { 125 | switch (ch) { 126 | case 's': 127 | sip_sorted = 1; 128 | break; 129 | case 'x': 130 | sort_err_fatal = 1; 131 | break; 132 | case '?': 133 | default: 134 | usage(); 135 | } 136 | } 137 | argc -= optind; 138 | argv += optind; 139 | 140 | if (argc < 1) 141 | usage(); 142 | SORTSIZE = atoi(argv[0]); 143 | if (SORTSIZE < 2) { 144 | fprintf(stderr, "sortsize should be greater than 1\n"); 145 | exit(1); 146 | } 147 | packets = calloc(SORTSIZE, sizeof(struct _pkt)); 148 | if (0 == packets) 149 | err(1, "calloc"); 150 | 151 | in = pcap_open_offline("-", errbuf); 152 | if (NULL == in) { 153 | fprintf(stderr, "stdin: %s", errbuf); 154 | exit(1); 155 | } 156 | out = pcap_dump_open(in, "-"); 157 | if (NULL == out) { 158 | perror("stdout"); 159 | exit(1); 160 | } 161 | if (sip_sorted) { 162 | pcap_layers_init(pcap_datalink(in), 0); 163 | callback_ipv4 = my_ip4_handler; 164 | callback_ipv6 = my_ip6_handler; 165 | } 166 | while ((data = pcap_next(in, &hdr))) { 167 | push(&hdr, data); 168 | if (sip_sorted) { 169 | handle_pcap(this_sip, &hdr, data); 170 | if (memcmp(this_sip, that_sip, 16)) { 171 | flush(out, 0); 172 | memcpy(that_sip, this_sip, 16); 173 | max_flushed.tv_sec = max_flushed.tv_usec = 0; 174 | } 175 | } 176 | if (SORTSIZE == npkts) 177 | flush(out, npkts / 2); 178 | } 179 | pcap_close(in); 180 | flush(out, 0); 181 | pcap_dump_close(out); 182 | exit(0); 183 | } 184 | -------------------------------------------------------------------------------- /pcap-sample.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "pcap-tools.h" 13 | 14 | const char *progname = 0; 15 | 16 | /* 17 | * Sample every Nth packet 18 | */ 19 | 20 | void 21 | usage(void) 22 | { 23 | fprintf(stderr, "usage: %s -n rate < pcap-in > pcap-out\n", progname); 24 | exit(1); 25 | } 26 | 27 | int 28 | main(int argc, char *argv[]) 29 | { 30 | pcap_t *in = NULL; 31 | pcap_dumper_t *out = NULL; 32 | struct pcap_pkthdr hdr; 33 | const u_char *data; 34 | int i; 35 | uint64_t samplerate = 0; 36 | uint64_t incount = 0; 37 | uint64_t outcount = 0; 38 | 39 | progname = argv[0]; 40 | while ((i = getopt(argc, argv, "n:")) != -1) { 41 | switch (i) { 42 | case 'n': 43 | samplerate = strtoul(optarg, 0, 10); 44 | break; 45 | case '?': 46 | default: 47 | usage(); 48 | } 49 | } 50 | argc -= optind; 51 | argv += optind; 52 | 53 | in = my_pcap_open_offline("-"); 54 | out = pcap_dump_open(in, "-"); 55 | if (NULL == out) { 56 | perror("stdout"); 57 | exit(1); 58 | } 59 | while ((data = pcap_next(in, &hdr))) { 60 | if (0 != (incount++ % samplerate)) 61 | continue; 62 | pcap_dump((void *) out, &hdr, data); 63 | outcount++; 64 | } 65 | my_pcap_close_offline(in); 66 | pcap_dump_close(out); 67 | fprintf(stderr, "%s: Read %" PRIu64 ", Wrote %" PRIu64 " packets\n", progname, incount, outcount); 68 | exit(0); 69 | } 70 | -------------------------------------------------------------------------------- /pcap-separate-by-connection.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include "pcap-tools.h" 24 | 25 | #define LIMIT_OPEN_FD 1024 26 | #define LIMIT_MAXRSS (256<<20) 27 | #define LIMIT_PKTS_IN_MEM (2<<20) 28 | #define QUAD_A(ip) ((ntohl(ip.u.in4.s_addr) >> 24) & 0xFF) 29 | #define QUAD_B(ip) ((ntohl(ip.u.in4.s_addr) >> 16) & 0xFF) 30 | #define QUAD_C(ip) ((ntohl(ip.u.in4.s_addr) >> 8) & 0xFF) 31 | #define QUAD_D(ip) ((ntohl(ip.u.in4.s_addr) ) & 0xFF) 32 | 33 | #ifdef __GLIBC__ 34 | #define __u6_addr __in6_u 35 | #define th_sport source 36 | #define th_dport dest 37 | #endif 38 | 39 | typedef struct _dlink_node dlink_node; 40 | typedef struct _dlink_list dlink_list; 41 | typedef struct _conn conn; 42 | typedef struct _tuple tuple; 43 | typedef struct _packet packet; 44 | typedef struct _inx_addr inx_addr; 45 | 46 | struct _dlink_node 47 | { 48 | void *data; 49 | dlink_node *prev; 50 | dlink_node *next; 51 | }; 52 | 53 | struct _dlink_list 54 | { 55 | dlink_node *head; 56 | dlink_node *tail; 57 | }; 58 | 59 | struct _packet 60 | { 61 | struct pcap_pkthdr hdr; 62 | void *data; 63 | packet *next; 64 | }; 65 | 66 | struct _inx_addr 67 | { 68 | uint8_t family; 69 | union 70 | { 71 | struct in_addr in4; 72 | struct in6_addr in6; 73 | } u; 74 | }; 75 | 76 | struct _tuple 77 | { 78 | inx_addr sip; 79 | inx_addr dip; 80 | unsigned short sport; 81 | unsigned short dport; 82 | }; 83 | 84 | struct _conn 85 | { 86 | tuple tuple; 87 | packet *pkthead; 88 | packet **pkttail; 89 | int npackets; 90 | pcap_dumper_t *fd; 91 | conn *next; 92 | dlink_node lru; 93 | }; 94 | 95 | #define HASH_SIZE 1037 96 | 97 | static struct _conn *Hash[HASH_SIZE]; 98 | static struct _dlink_list *LRU; 99 | static unsigned int nopen = 3; 100 | static unsigned int nconn = 0; 101 | static unsigned int npacketsmem = 0; 102 | static pcap_t *in = NULL; 103 | static int use_subdirs = 1; /* write files into subdirs */ 104 | static uint64_t pkts_read = 0; 105 | static uint64_t pkts_writ = 0; 106 | static uint64_t pkts_stashed = 0; 107 | 108 | unsigned int 109 | inx_addr_hash(inx_addr a) 110 | { 111 | if (AF_INET == a.family) 112 | return QUAD_B(a) + QUAD_C(a); 113 | return 0; 114 | } 115 | 116 | unsigned int 117 | tuple_hash(tuple * t) 118 | { 119 | return (inx_addr_hash(t->sip) + inx_addr_hash(t->dip) + t->sport + t->dport) % HASH_SIZE; 120 | } 121 | 122 | int 123 | inx_addr_equal(inx_addr a, inx_addr b) 124 | { 125 | if (a.family != b.family) 126 | return 0; 127 | if (AF_INET == a.family) 128 | return a.u.in4.s_addr == b.u.in4.s_addr; 129 | return 0 == memcmp(&a.u.in6, &b.u.in6, 16); 130 | } 131 | 132 | int 133 | tuple_equal(tuple * a, tuple * b) 134 | { 135 | if ((a->sport == b->sport) && 136 | (a->dport == b->dport) && inx_addr_equal(a->sip, b->sip) && inx_addr_equal(a->dip, b->dip)) 137 | return 1; 138 | if ((a->sport == b->dport) && 139 | (a->dport == b->sport) && inx_addr_equal(a->sip, b->dip) && inx_addr_equal(a->dip, b->sip)) 140 | return 1; 141 | return 0; 142 | } 143 | 144 | void 145 | dlinkAdd(void *data, dlink_node * m, dlink_list * list) 146 | { 147 | m->data = data; 148 | m->prev = NULL; 149 | m->next = list->head; 150 | if (list->head) 151 | list->head->prev = m; 152 | list->head = m; 153 | if (list->tail == NULL) 154 | list->tail = m; 155 | } 156 | 157 | void 158 | dlinkDelete(dlink_node * m, dlink_list * list) 159 | { 160 | if (m->next) 161 | m->next->prev = m->prev; 162 | if (m->prev) 163 | m->prev->next = m->next; 164 | if (m == list->head) 165 | list->head = m->next; 166 | if (m == list->tail) 167 | list->tail = m->prev; 168 | m->next = m->prev = NULL; 169 | } 170 | 171 | void 172 | hashDelete(conn * f) 173 | { 174 | unsigned int i = tuple_hash(&f->tuple); 175 | conn **F; 176 | for (F = &Hash[i]; *F; F = &(*F)->next) 177 | if (f == *F) { 178 | *F = f->next; 179 | break; 180 | } 181 | } 182 | 183 | void 184 | mksubdir(const char *path) 185 | { 186 | char *t; 187 | for (t = (char *) path; *t; t++) { 188 | if ('/' == *t) { 189 | *t = '\0'; 190 | if (mkdir(path, 0755) < 0 && EEXIST != errno) { 191 | perror(path); 192 | exit(1); 193 | } 194 | *t = '/'; 195 | } 196 | } 197 | } 198 | 199 | const char * 200 | output_fname(const conn * f) 201 | { 202 | static char fname[768]; 203 | static char src_s[128]; 204 | static char dst_s[128]; 205 | inet_ntop(f->tuple.sip.family, &f->tuple.sip.u, src_s, sizeof(src_s)); 206 | inet_ntop(f->tuple.dip.family, &f->tuple.dip.u, dst_s, sizeof(dst_s)); 207 | snprintf(fname, sizeof(fname), 208 | "%s/%u/%s/%s:%u-%s:%u@%lu.%06lu.pcap", 209 | src_s, 210 | f->tuple.sport, 211 | dst_s, 212 | src_s, 213 | f->tuple.sport, dst_s, f->tuple.dport, f->pkthead->hdr.ts.tv_sec, (unsigned long) f->pkthead->hdr.ts.tv_usec); 214 | return fname; 215 | } 216 | 217 | 218 | void 219 | conn_pcap_open(conn * f) 220 | { 221 | const char *file; 222 | if (NULL != f->fd) 223 | return; 224 | file = output_fname(f); 225 | f->fd = pcap_dump_open(in, file); 226 | if (NULL == f->fd && errno == ENOENT) { 227 | mksubdir(file); 228 | f->fd = pcap_dump_open(in, file); 229 | } 230 | if (NULL == f->fd) { 231 | perror(file); 232 | exit(1); 233 | } 234 | nopen++; 235 | } 236 | 237 | 238 | void 239 | conn_free_packets(conn * f) 240 | { 241 | packet *p; 242 | packet *n; 243 | for (p = f->pkthead; p; p = n) { 244 | n = p->next; 245 | free(p->data); 246 | free(p); 247 | } 248 | npacketsmem -= f->npackets; 249 | f->npackets = 0; 250 | f->pkthead = NULL; 251 | f->pkttail = &f->pkthead; 252 | } 253 | 254 | void 255 | conn_pcap_write(conn * f) 256 | { 257 | packet *p; 258 | if (0 == f->npackets) 259 | return; 260 | for (p = f->pkthead; p; p = p->next) { 261 | pcap_dump((void *) f->fd, &p->hdr, p->data); 262 | pkts_writ++; 263 | } 264 | conn_free_packets(f); 265 | } 266 | 267 | void 268 | conn_pcap_close(conn * f) 269 | { 270 | if (NULL == f->fd) 271 | return; 272 | pcap_dump_close(f->fd); 273 | nopen--; 274 | f->fd = NULL; 275 | } 276 | 277 | void 278 | conn_free(conn * f) 279 | { 280 | if (f->npackets) 281 | conn_free_packets(f); 282 | hashDelete(f); 283 | dlinkDelete(&f->lru, LRU); 284 | free(f); 285 | nconn--; 286 | } 287 | 288 | void 289 | close_lru(void) 290 | { 291 | int nc = 0; 292 | dlink_node *p = LRU->tail; 293 | fprintf(stderr, "Closing LRU..."); 294 | while (nopen > (LIMIT_OPEN_FD / 2) && p) { 295 | conn *f = p->data; 296 | p = p->prev; 297 | if (NULL == f->fd) 298 | continue; 299 | conn_pcap_write(f); 300 | conn_pcap_close(f); 301 | conn_free(f); 302 | nc++; 303 | } 304 | fprintf(stderr, "%d\n", nc); 305 | } 306 | 307 | void 308 | flush(conn * f) 309 | { 310 | if (nopen >= LIMIT_OPEN_FD) 311 | close_lru(); 312 | conn_pcap_open(f); 313 | conn_pcap_write(f); 314 | } 315 | 316 | long 317 | getmaxrss(void) 318 | { 319 | struct rusage ru; 320 | getrusage(RUSAGE_SELF, &ru); 321 | return ru.ru_maxrss; 322 | } 323 | 324 | void 325 | flushall() 326 | { 327 | int i; 328 | int n = 0; 329 | conn *f; 330 | conn *next; 331 | fprintf(stderr, "Flushing...\n"); 332 | for (i = 0; i < HASH_SIZE; i++) { 333 | for (f = Hash[i]; f; f = next) { 334 | next = f->next; 335 | if (0 == f->npackets) 336 | continue; 337 | if (f->fd == NULL) 338 | conn_pcap_open(f); 339 | conn_pcap_write(f); 340 | n++; 341 | if (0 == (n % 1000)) 342 | fprintf(stderr, "flushed %d conns, open fd: %d\n", n, nopen); 343 | if (nopen >= LIMIT_OPEN_FD) 344 | close_lru(); 345 | } 346 | } 347 | fprintf(stderr, "flushed %d\n", n); 348 | fprintf(stderr, "open files: %d\n", nopen); 349 | fprintf(stderr, "max rss: %ld\n", getmaxrss()); 350 | } 351 | 352 | void 353 | stash2(conn * f, struct pcap_pkthdr *hdr, const unsigned char *data) 354 | { 355 | packet *p = calloc(1, sizeof(*p)); 356 | assert(p); 357 | p->hdr = *hdr; 358 | p->data = malloc(hdr->caplen); 359 | assert(p->data); 360 | memcpy(p->data, data, hdr->caplen); 361 | *f->pkttail = p; 362 | f->pkttail = &p->next; 363 | f->npackets++; 364 | npacketsmem++; 365 | } 366 | 367 | void 368 | stash(tuple * t, struct pcap_pkthdr *hdr, const unsigned char *data) 369 | { 370 | conn **F; 371 | conn *f; 372 | int i = tuple_hash(t); 373 | for (F = &Hash[i]; (f = *F); F = &(*F)->next) { 374 | if (tuple_equal(&f->tuple, t)) 375 | break; 376 | } 377 | if (NULL == f) { 378 | nconn++; 379 | f = calloc(1, sizeof(*f)); 380 | assert(f); 381 | f->tuple = *t; 382 | f->pkttail = &f->pkthead; 383 | f->next = Hash[i]; 384 | Hash[i] = f; 385 | } else if (f != Hash[i]) { 386 | /* move to top */ 387 | *F = f->next; 388 | f->next = Hash[i]; 389 | Hash[i] = f; 390 | } 391 | stash2(f, hdr, data); 392 | dlinkDelete(&f->lru, LRU); 393 | dlinkAdd(f, &f->lru, LRU); 394 | } 395 | 396 | void 397 | print_stats(struct timeval ts) 398 | { 399 | struct timeval now; 400 | gettimeofday(&now, NULL); 401 | fprintf(stderr, 402 | "%ld.%03ld: at %ld, %12" PRIu64 " read, %12" PRIu64 " stashed, %12" PRIu64 " writ, %9d conns, %4d files\n", 403 | (long) now.tv_sec, (long) now.tv_usec / 1000, (long) ts.tv_sec, pkts_read, pkts_stashed, pkts_writ, nconn, 404 | nopen); 405 | } 406 | 407 | int 408 | my_tcp_handler(const struct tcphdr *tcp, int len, void *userdata) 409 | { 410 | tuple *t = userdata; 411 | t->sport = nptohs(&tcp->th_sport); 412 | t->dport = nptohs(&tcp->th_dport); 413 | return 0; 414 | } 415 | 416 | int 417 | my_ip4_handler(const struct ip *ip4, int len, void *userdata) 418 | { 419 | tuple *t = userdata; 420 | t->sip.family = AF_INET; 421 | t->sip.u.in4 = ip4->ip_src; 422 | t->dip.family = AF_INET; 423 | t->dip.u.in4 = ip4->ip_dst; 424 | return 0; 425 | } 426 | 427 | int 428 | my_ip6_handler(const struct ip6_hdr *ip6, int len, void *userdata) 429 | { 430 | tuple *t = userdata; 431 | t->sip.family = AF_INET6; 432 | t->sip.u.in6 = ip6->ip6_src; 433 | t->dip.family = AF_INET6; 434 | t->dip.u.in6 = ip6->ip6_dst; 435 | return 0; 436 | } 437 | 438 | int 439 | main(int argc, char *argv[]) 440 | { 441 | char errbuf[PCAP_ERRBUF_SIZE + 1]; 442 | struct pcap_pkthdr hdr; 443 | const u_char *data; 444 | char *filterstr = NULL; 445 | struct bpf_program fp; 446 | int ch; 447 | 448 | setbuf(stdout, NULL); 449 | setbuf(stderr, NULL); 450 | memset(Hash, '\0', sizeof(Hash)); 451 | LRU = calloc(1, sizeof(LRU)); 452 | assert(LRU); 453 | 454 | // Process command line 455 | while ((ch = getopt(argc, argv, "bf:ls")) != -1) { 456 | switch (ch) { 457 | case 'b': 458 | filterstr = strdup(optarg); 459 | break; 460 | case 'l': 461 | use_subdirs = 0; 462 | break; 463 | default: 464 | fprintf(stderr, "usage: %s [-l] [-b bpfprogram]\n", argv[0]); 465 | exit(1); 466 | break; 467 | } 468 | } 469 | argc -= optind; 470 | argv += optind; 471 | 472 | in = pcap_open_offline("-", errbuf); 473 | if (NULL == in) { 474 | fprintf(stderr, "stdin: %s", errbuf); 475 | exit(1); 476 | } 477 | // Set the filter 478 | if (NULL != filterstr) { 479 | memset(&fp, '\0', sizeof(fp)); 480 | if (pcap_compile(in, &fp, filterstr, 1, 0) < 0) { 481 | fprintf(stderr, "pcap_compile failed: %s\n", pcap_geterr(in)); 482 | exit(1); 483 | } 484 | if (pcap_setfilter(in, &fp) < 0) { 485 | fprintf(stderr, "pcap_setfilter failed: %s\n", pcap_geterr(in)); 486 | exit(1); 487 | } 488 | fprintf(stderr, "Filter read and compiled!\n"); 489 | } 490 | 491 | pcap_layers_init(pcap_datalink(in), 0); 492 | callback_tcp = my_tcp_handler; 493 | callback_ipv4 = my_ip4_handler; 494 | callback_ipv6 = my_ip6_handler; 495 | 496 | while ((data = pcap_next(in, &hdr))) { 497 | tuple T; 498 | memset(&T, 0, sizeof(T)); 499 | pkts_read++; 500 | handle_pcap((u_char *) & T, &hdr, data); 501 | if (T.sip.family == 0) 502 | continue; 503 | if (0 == T.sport && 0 == T.dport) 504 | continue; 505 | stash(&T, &hdr, data); 506 | if (0 == (++pkts_stashed & 0x3FFF)) { 507 | print_stats(hdr.ts); 508 | if (npacketsmem > LIMIT_PKTS_IN_MEM) { 509 | flushall(); 510 | } 511 | } 512 | } 513 | flushall(); 514 | print_stats(hdr.ts); 515 | fprintf(stderr, "Max RSS %ld KB \n", getmaxrss()); 516 | return 0; 517 | } 518 | -------------------------------------------------------------------------------- /pcap-separate-by-sip.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include "pcap_layers.h" 23 | 24 | #define LIMIT_OPEN_FD 8192 25 | #define LIMIT_CLT_PKTS 2048 26 | #define LIMIT_MAXRSS (256<<20) 27 | #define LIMIT_PKTS_IN_MEM (1<<24) 28 | #define QUAD_A(ip) ((ntohl(ip.u.in4.s_addr) >> 24) & 0xFF) 29 | #define QUAD_B(ip) ((ntohl(ip.u.in4.s_addr) >> 16) & 0xFF) 30 | #define QUAD_C(ip) ((ntohl(ip.u.in4.s_addr) >> 8) & 0xFF) 31 | #define QUAD_D(ip) ((ntohl(ip.u.in4.s_addr) ) & 0xFF) 32 | 33 | #define MAX_FILTER_SZ 256*1024 34 | 35 | typedef struct _dlink_node dlink_node; 36 | typedef struct _dlink_list dlink_list; 37 | 38 | struct _dlink_node 39 | { 40 | void *data; 41 | dlink_node *prev; 42 | dlink_node *next; 43 | }; 44 | 45 | struct _dlink_list 46 | { 47 | dlink_node *head; 48 | dlink_node *tail; 49 | }; 50 | 51 | struct _packet 52 | { 53 | struct pcap_pkthdr hdr; 54 | void *data; 55 | struct _packet *next; 56 | }; 57 | 58 | struct inx_addr 59 | { 60 | uint8_t family; 61 | union 62 | { 63 | struct in_addr in4; 64 | struct in6_addr in6; 65 | } u; 66 | }; 67 | 68 | struct _client 69 | { 70 | struct inx_addr addr; 71 | struct _packet *pkthead; 72 | struct _packet **pkttail; 73 | int npackets; 74 | pcap_dumper_t *fd; 75 | struct _client *next; 76 | dlink_node lru; 77 | }; 78 | 79 | static struct _client *Hash[256]; 80 | static struct _dlink_list *LRU; 81 | static unsigned int nopen = 3; 82 | static unsigned int nclts = 0; 83 | static unsigned int npacketsmem = 0; 84 | static pcap_t *in = NULL; 85 | static int input_sorted = 0; /* assume input already sorted by sip */ 86 | static int use_subdirs = 1; /* write files into subdirs */ 87 | static int use_mask = 0; /* mask source IPs */ 88 | static struct inx_addr v4mask; 89 | static struct inx_addr v6mask; 90 | 91 | int 92 | inx_addr_hash(struct inx_addr a) 93 | { 94 | if (AF_INET == a.family) 95 | return QUAD_A(a); 96 | else if (AF_INET6 == a.family) 97 | return a.u.in6.s6_addr[3]; 98 | return 0; 99 | } 100 | 101 | int 102 | inx_addr_equal(struct inx_addr a, struct inx_addr b) 103 | { 104 | if (a.family != b.family) 105 | return 0; 106 | if (AF_INET == a.family) 107 | return a.u.in4.s_addr == b.u.in4.s_addr; 108 | return 0 == memcmp(&a.u.in6, &b.u.in6, 16); 109 | } 110 | 111 | void 112 | dlinkAdd(void *data, dlink_node * m, dlink_list * list) 113 | { 114 | m->data = data; 115 | m->prev = NULL; 116 | m->next = list->head; 117 | if (list->head) 118 | list->head->prev = m; 119 | list->head = m; 120 | if (list->tail == NULL) 121 | list->tail = m; 122 | } 123 | 124 | void 125 | dlinkDelete(dlink_node * m, dlink_list * list) 126 | { 127 | if (m->next) 128 | m->next->prev = m->prev; 129 | if (m->prev) 130 | m->prev->next = m->next; 131 | if (m == list->head) 132 | list->head = m->next; 133 | if (m == list->tail) 134 | list->tail = m->prev; 135 | m->next = m->prev = NULL; 136 | } 137 | 138 | void 139 | hashDelete(struct _client *f) 140 | { 141 | int i = inx_addr_hash(f->addr); 142 | struct _client **F; 143 | for (F = &Hash[i]; *F; F = &(*F)->next) 144 | if (f == *F) { 145 | *F = f->next; 146 | break; 147 | } 148 | } 149 | 150 | void 151 | mksubdir(const char *path) 152 | { 153 | char *t; 154 | for (t = (char *) path; *t; t++) { 155 | if ('/' == *t) { 156 | *t = '\0'; 157 | if (mkdir(path, 0755) < 0 && EEXIST != errno) { 158 | perror(path); 159 | exit(1); 160 | } 161 | *t = '/'; 162 | } 163 | } 164 | } 165 | 166 | const char * 167 | output_fname(const struct _client *f) 168 | { 169 | unsigned int l = 0; 170 | static char fname[256]; 171 | static char aname[128]; 172 | inet_ntop(f->addr.family, &f->addr.u, aname, sizeof(aname)); 173 | if (use_subdirs && AF_INET == f->addr.family) { 174 | l += snprintf(&fname[l], sizeof(fname) - l, "%03d/", QUAD_A(f->addr)); 175 | l += snprintf(&fname[l], sizeof(fname) - l, "%03d/", QUAD_B(f->addr)); 176 | } else if (use_subdirs && AF_INET6 == f->addr.family) { 177 | unsigned short v6[8]; 178 | memcpy(&v6[0], &f->addr.u.in6.s6_addr, 16); 179 | l += snprintf(&fname[l], sizeof(fname) - l, "%04x/", v6[0]); 180 | l += snprintf(&fname[l], sizeof(fname) - l, "%04x/", v6[1]); 181 | } 182 | l += snprintf(&fname[l], sizeof(fname) - l, "%s", aname); 183 | if (!input_sorted) 184 | l += snprintf(&fname[l], sizeof(fname) - l, "/%lu.%06lu", 185 | (long unsigned int) f->pkthead->hdr.ts.tv_sec, (long unsigned int) f->pkthead->hdr.ts.tv_usec); 186 | l += snprintf(&fname[l], sizeof(fname) - l, "%s", ".pcap"); 187 | assert(l < sizeof(fname)); 188 | return fname; 189 | } 190 | 191 | 192 | void 193 | clt_pcap_open(struct _client *f) 194 | { 195 | const char *file; 196 | if (NULL != f->fd) 197 | return; 198 | file = output_fname(f); 199 | if (input_sorted) { 200 | struct stat sb; 201 | if (0 == stat(file, &sb)) { 202 | fprintf(stderr, "%s already exist, perhaps input is not sorted?\n", file); 203 | exit(1); 204 | } 205 | } 206 | f->fd = pcap_dump_open(in, file); 207 | if (NULL == f->fd && errno == ENOENT) { 208 | mksubdir(file); 209 | f->fd = pcap_dump_open(in, file); 210 | } 211 | if (NULL == f->fd) { 212 | perror(file); 213 | exit(1); 214 | } 215 | nopen++; 216 | } 217 | 218 | 219 | void 220 | clt_free_packets(struct _client *f) 221 | { 222 | struct _packet *p; 223 | struct _packet *n; 224 | for (p = f->pkthead; p; p = n) { 225 | n = p->next; 226 | free(p->data); 227 | free(p); 228 | } 229 | npacketsmem -= f->npackets; 230 | f->npackets = 0; 231 | f->pkthead = NULL; 232 | f->pkttail = &f->pkthead; 233 | } 234 | 235 | void 236 | clt_pcap_write(struct _client *f) 237 | { 238 | struct _packet *p; 239 | if (0 == f->npackets) 240 | return; 241 | for (p = f->pkthead; p; p = p->next) 242 | pcap_dump((void *) f->fd, &p->hdr, p->data); 243 | clt_free_packets(f); 244 | } 245 | 246 | void 247 | clt_pcap_close(struct _client *f) 248 | { 249 | if (NULL == f->fd) 250 | return; 251 | pcap_dump_close(f->fd); 252 | nopen--; 253 | f->fd = NULL; 254 | } 255 | 256 | void 257 | clt_free(struct _client *f) 258 | { 259 | if (f->npackets) 260 | clt_free_packets(f); 261 | hashDelete(f); 262 | dlinkDelete(&f->lru, LRU); 263 | free(f); 264 | nclts--; 265 | } 266 | 267 | void 268 | close_lru(void) 269 | { 270 | int nc = 0; 271 | dlink_node *p = LRU->tail; 272 | fprintf(stderr, "Closing LRU..."); 273 | while (nopen > (LIMIT_OPEN_FD / 2) && p) { 274 | struct _client *f = p->data; 275 | p = p->prev; 276 | if (NULL == f->fd) 277 | continue; 278 | clt_pcap_write(f); 279 | clt_pcap_close(f); 280 | /* clt_free(f); */ 281 | nc++; 282 | } 283 | fprintf(stderr, "%d\n", nc); 284 | } 285 | 286 | void 287 | flush(struct _client *f) 288 | { 289 | if (nopen >= LIMIT_OPEN_FD) 290 | close_lru(); 291 | clt_pcap_open(f); 292 | clt_pcap_write(f); 293 | } 294 | 295 | long 296 | getmaxrss(void) 297 | { 298 | struct rusage ru; 299 | getrusage(RUSAGE_SELF, &ru); 300 | return ru.ru_maxrss; 301 | } 302 | 303 | void 304 | flushall() 305 | { 306 | int i; 307 | int n = 0; 308 | struct _client *f; 309 | struct _client *next; 310 | fprintf(stderr, "Flushing...\n"); 311 | for (i = 0; i < 256; i++) { 312 | for (f = Hash[i]; f; f = next) { 313 | next = f->next; 314 | if (0 == f->npackets) 315 | continue; 316 | if (f->fd == NULL) 317 | clt_pcap_open(f); 318 | clt_pcap_write(f); 319 | n++; 320 | if (0 == (n % 1000)) 321 | fprintf(stderr, "flushed %d clts, open fd: %d\n", n, nopen); 322 | if (nopen >= LIMIT_OPEN_FD) 323 | close_lru(); 324 | } 325 | } 326 | fprintf(stderr, "flushed %d\n", n); 327 | fprintf(stderr, "open files: %d\n", nopen); 328 | fprintf(stderr, "max rss: %ld\n", getmaxrss()); 329 | } 330 | 331 | void 332 | stash2(struct _client *f, struct pcap_pkthdr *hdr, const unsigned char *data) 333 | { 334 | struct _packet *p = calloc(1, sizeof(*p)); 335 | assert(p); 336 | p->hdr = *hdr; 337 | p->data = malloc(hdr->caplen); 338 | assert(p->data); 339 | memcpy(p->data, data, hdr->caplen); 340 | *f->pkttail = p; 341 | f->pkttail = &p->next; 342 | f->npackets++; 343 | npacketsmem++; 344 | #if 0 345 | if (f->npackets > LIMIT_CLT_PKTS) 346 | flush(f); 347 | #endif 348 | } 349 | 350 | void 351 | stash(struct inx_addr a, struct pcap_pkthdr *hdr, const unsigned char *data) 352 | { 353 | struct _client **F; 354 | struct _client *f; 355 | int i = inx_addr_hash(a); 356 | for (F = &Hash[i]; (f = *F); F = &(*F)->next) { 357 | if (inx_addr_equal(f->addr, a)) 358 | break; 359 | } 360 | if (NULL == f) { 361 | nclts++; 362 | f = calloc(1, sizeof(*f)); 363 | assert(f); 364 | f->addr = a; 365 | f->pkttail = &f->pkthead; 366 | f->next = Hash[i]; 367 | Hash[i] = f; 368 | } else if (f != Hash[i]) { 369 | /* move to top */ 370 | *F = f->next; 371 | f->next = Hash[i]; 372 | Hash[i] = f; 373 | } 374 | stash2(f, hdr, data); 375 | dlinkDelete(&f->lru, LRU); 376 | dlinkAdd(f, &f->lru, LRU); 377 | } 378 | 379 | void 380 | print_stats(struct timeval ts, uint64_t pkt_count) 381 | { 382 | struct timeval now; 383 | gettimeofday(&now, NULL); 384 | fprintf(stderr, "%ld.%03ld: at %ld, %12" PRIu64 " pkts, %9d clts, %4d files\n", 385 | (long) now.tv_sec, (long) now.tv_usec / 1000, (long) ts.tv_sec, pkt_count, nclts, nopen); 386 | } 387 | 388 | int 389 | my_ip4_handler(const struct ip *ip4, int len, void *userdata) 390 | { 391 | struct inx_addr *a = userdata; 392 | a->family = AF_INET; 393 | a->u.in4 = ip4->ip_src; 394 | if (use_mask) 395 | a->u.in4.s_addr &= v4mask.u.in4.s_addr; 396 | return 0; 397 | } 398 | 399 | int 400 | my_ip6_handler(const struct ip6_hdr *ip6, int len, void *userdata) 401 | { 402 | struct inx_addr *a = userdata; 403 | a->family = AF_INET6; 404 | a->u.in6 = ip6->ip6_src; 405 | if (use_mask) { 406 | int i; 407 | for (i = 0; i < 16; i++) 408 | a->u.in6.s6_addr[i] &= v6mask.u.in6.s6_addr[i]; 409 | } 410 | return 0; 411 | } 412 | 413 | int 414 | is_rfc1918(struct inx_addr a) 415 | { 416 | unsigned long clt_addr = ntohl(a.u.in4.s_addr); 417 | if (AF_INET != a.family) 418 | return 0; 419 | //10 / 8 420 | if ((clt_addr & 0xff000000) == 0x0A000000) 421 | return 1; 422 | //172.16 / 12 423 | if ((clt_addr & 0xfff00000) == 0xAC100000) 424 | return 1; 425 | //192.168 / 16 426 | if ((clt_addr & 0xffff0000) == 0xC0A80000) 427 | return 1; 428 | 429 | return 0; 430 | } 431 | 432 | 433 | int 434 | main(int argc, char *argv[]) 435 | { 436 | uint64_t pkt_count = 0; 437 | char errbuf[PCAP_ERRBUF_SIZE + 1]; 438 | struct pcap_pkthdr hdr; 439 | const u_char *data; 440 | char *filterstr = NULL; 441 | char *filterfile = NULL; 442 | FILE *FP = NULL; 443 | char buf[80]; 444 | char or_str[4] = "\0"; 445 | char lc = 0; 446 | struct bpf_program fp; 447 | int ch; 448 | int skip_bogon = 0; 449 | 450 | setbuf(stdout, NULL); 451 | setbuf(stderr, NULL); 452 | memset(Hash, '\0', sizeof(Hash)); 453 | LRU = calloc(1, sizeof(LRU)); 454 | assert(LRU); 455 | 456 | //Process command line 457 | while ((ch = getopt(argc, argv, "bf:lsm")) != -1) { 458 | switch (ch) { 459 | case 'b': 460 | skip_bogon = 1; 461 | break; 462 | case 'f': 463 | filterfile = strdup(optarg); 464 | break; 465 | case 'l': 466 | use_subdirs = 0; 467 | break; 468 | case 's': 469 | input_sorted = 1; 470 | break; 471 | case 'm': 472 | use_mask = 1; 473 | break; 474 | default: 475 | fprintf(stderr, "usage: %s -b -f addr_list_file -l -s -m\n", argv[0]); 476 | fprintf(stderr, "\t-b\tskip bogons\n"); 477 | fprintf(stderr, "\t-f file\tbpf filter file\n"); 478 | fprintf(stderr, "\t-l\tuse subdirectories\n"); 479 | fprintf(stderr, "\t-s\tinput is sorted by IP\n"); 480 | fprintf(stderr, "\t-m\tmask source IPs\n"); 481 | exit(1); 482 | break; 483 | } 484 | } 485 | argc -= optind; 486 | argv += optind; 487 | 488 | if (NULL != filterfile) { 489 | //If a filter file was given, read it and prepare 490 | if ((FP = fopen(filterfile, "r")) == NULL) { 491 | fprintf(stderr, "Can't read filter file %s, aborting\n", filterfile); 492 | exit(1); 493 | } 494 | filterstr = (char *) calloc(1, MAX_FILTER_SZ); 495 | while (fgets(buf, 80, FP)) { 496 | if (strlen(filterstr) > MAX_FILTER_SZ - 12) 497 | continue; 498 | 499 | if (lc != 0) 500 | strcpy(or_str, "or"); 501 | snprintf(filterstr, MAX_FILTER_SZ, "%s %s src net %s", filterstr, or_str, buf); 502 | ++lc; 503 | } 504 | fclose(FP); 505 | 506 | //For debugging purporses, write the filter 507 | FILE *filter_fp = fopen("filter_pcap.dat", "w"); 508 | if (NULL == filter_fp) 509 | fprintf(stderr, "Can't write filter, skipping\n"); 510 | else { 511 | fprintf(filter_fp, "%s\n", filterstr); 512 | fclose(filter_fp); 513 | } 514 | } 515 | in = pcap_open_offline("-", errbuf); 516 | if (NULL == in) { 517 | fprintf(stderr, "stdin: %s", errbuf); 518 | exit(1); 519 | } 520 | //Set the filter 521 | if (NULL != filterstr) { 522 | memset(&fp, '\0', sizeof(fp)); 523 | if (pcap_compile(in, &fp, filterstr, 1, 0) < 0) { 524 | fprintf(stderr, "pcap_compile failed: %s\n", pcap_geterr(in)); 525 | exit(1); 526 | } 527 | if (pcap_setfilter(in, &fp) < 0) { 528 | fprintf(stderr, "pcap_setfilter failed: %s\n", pcap_geterr(in)); 529 | exit(1); 530 | } 531 | fprintf(stderr, "Filter read and compiled!\n"); 532 | } 533 | assert(inet_pton(AF_INET, "255.0.0.0", &v4mask.u.in4)); 534 | assert(inet_pton(AF_INET6, "ffff::", &v6mask.u.in4)); 535 | 536 | pcap_layers_init(pcap_datalink(in), 0); 537 | callback_ipv4 = my_ip4_handler; 538 | callback_ipv6 = my_ip6_handler; 539 | 540 | while ((data = pcap_next(in, &hdr))) { 541 | struct inx_addr src; 542 | memset(&src, 0, sizeof(src)); 543 | handle_pcap((u_char *) & src, &hdr, data); 544 | if (src.family == 0) 545 | continue; 546 | if (skip_bogon && is_rfc1918(src)) 547 | continue; 548 | stash(src, &hdr, data); 549 | if (0 == (++pkt_count & 0x3FFF)) { 550 | print_stats(hdr.ts, pkt_count); 551 | if (npacketsmem > LIMIT_PKTS_IN_MEM) { 552 | flushall(); 553 | close_lru(); 554 | } 555 | } 556 | } 557 | flushall(); 558 | fprintf(stderr, "Max RSS %ld KB \n", getmaxrss()); 559 | return 0; 560 | } 561 | -------------------------------------------------------------------------------- /pcap-separate.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "pcap_layers.h" 10 | 11 | struct _item 12 | { 13 | struct in_addr addr; 14 | pcap_dumper_t *out; 15 | struct _item *next; 16 | }; 17 | struct _item *List; 18 | 19 | void 20 | read_list(const char *fn, pcap_t * in) 21 | { 22 | FILE *fp = fopen(fn, "r"); 23 | struct _item **tailp = &List; 24 | char buf[512]; 25 | char ofn[768]; 26 | if (NULL == fp) { 27 | perror(fn); 28 | exit(1); 29 | } 30 | while (NULL != fgets(buf, 512, fp)) { 31 | struct _item *i = calloc(1, sizeof(*i)); 32 | strtok(buf, "\r\n"); 33 | i->addr.s_addr = inet_addr(buf); 34 | snprintf(ofn, sizeof(ofn), "%s.pcap", buf); 35 | i->out = pcap_dump_open(in, ofn); 36 | if (NULL == i->out) { 37 | perror(ofn); 38 | exit(1); 39 | } 40 | *(tailp) = i; 41 | tailp = &i->next; 42 | } 43 | } 44 | 45 | struct _item * 46 | search(const struct in_addr a) 47 | { 48 | struct _item *i; 49 | for (i = List; i; i = i->next) 50 | if (i->addr.s_addr == a.s_addr) 51 | return i; 52 | return NULL; 53 | } 54 | 55 | 56 | int 57 | my_ip4_handler(const struct ip *ip4, int len, void *userdata) 58 | { 59 | struct in_addr *a = userdata; 60 | *a = ip4->ip_src; 61 | return 0; 62 | } 63 | 64 | 65 | int 66 | main(int argc, char *argv[]) 67 | { 68 | pcap_t *in = NULL; 69 | char errbuf[PCAP_ERRBUF_SIZE + 1]; 70 | struct pcap_pkthdr hdr; 71 | const u_char *data; 72 | struct _item *i; 73 | 74 | if (2 != argc) { 75 | fprintf(stderr, "usage: pcap-separate listfile\n"); 76 | exit(1); 77 | } 78 | 79 | in = pcap_open_offline("-", errbuf); 80 | if (NULL == in) { 81 | fprintf(stderr, "stdin: %s", errbuf); 82 | exit(1); 83 | } 84 | read_list(argv[1], in); 85 | pcap_layers_init(pcap_datalink(in), 0); 86 | callback_ipv4 = my_ip4_handler; 87 | 88 | while ((data = pcap_next(in, &hdr))) { 89 | struct in_addr src; 90 | memset(&src, 0, sizeof(src)); 91 | handle_pcap((u_char *) & src, &hdr, data); 92 | i = search(src); 93 | if (NULL == i) 94 | continue; 95 | pcap_dump((void *) i->out, &hdr, data); 96 | } 97 | 98 | for (i = List; i; i = i->next) 99 | pcap_dump_close(i->out); 100 | exit(0); 101 | } 102 | -------------------------------------------------------------------------------- /pcap-sort-by-sip.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "pcap-tools.h" 19 | #include "pcap_layers.h" 20 | 21 | 22 | #define N_SPLIT 256 23 | #define MAX_LEVELS 16 /* 4 for IPv4, 16 for IPv6 */ 24 | static int theLevel = 0; 25 | 26 | /* 27 | * the tmpdirs array holds temp dir names that should be 'rm -rf'd 28 | * if the program exits unexpectedly. 29 | */ 30 | #define TMPDIRNAMESZ 128 31 | static char tmpdirs[MAX_LEVELS][TMPDIRNAMESZ]; 32 | 33 | int 34 | my_ip4_af_setter(const struct ip *ip4, int len, void *userdata) 35 | { 36 | *((sa_family_t *) userdata) = AF_INET; 37 | return 0; 38 | } 39 | 40 | int 41 | my_ip6_af_setter(const struct ip6_hdr *ip6, int len, void *userdata) 42 | { 43 | *((sa_family_t *) userdata) = AF_INET6; 44 | return 0; 45 | } 46 | 47 | int 48 | my_ip4_handler(const struct ip *ip4, int len, void *userdata) 49 | { 50 | *((int *) userdata) = ntohl(ip4->ip_src.s_addr) >> (theLevel << 3) & 0xFF; 51 | return 0; 52 | } 53 | 54 | int 55 | my_ip6_handler(const struct ip6_hdr *ip6, int len, void *userdata) 56 | { 57 | *((int *) userdata) = ip6->ip6_src.s6_addr[15 - theLevel]; 58 | return 0; 59 | } 60 | 61 | void 62 | cleanup(int sig) 63 | { 64 | int i; 65 | char cmd[256]; 66 | for (i = 0; i < 16; i++) { 67 | if ('\0' == tmpdirs[i][0]) 68 | continue; 69 | snprintf(cmd, sizeof(cmd), "/bin/rm -r %s", tmpdirs[i]); 70 | system(cmd); 71 | } 72 | exit(1); 73 | } 74 | 75 | pcap_dumper_t * 76 | my_pcap_dump_open(pcap_t * other, const char *f) 77 | { 78 | pcap_dumper_t *out; 79 | out = pcap_dump_open(other, f); 80 | if (NULL == out) 81 | errx(1, "%s", f); 82 | return out; 83 | } 84 | 85 | void 86 | pcap_sort(const char *inf, const char *outf, int level) 87 | { 88 | pcap_t *in = NULL; 89 | pcap_dumper_t *pcap_out = NULL; 90 | pcap_dumper_t *out[N_SPLIT]; 91 | struct pcap_pkthdr hdr; 92 | const u_char *data; 93 | int i; 94 | const char *dir; 95 | static char *twhiler = "-\\|/"; 96 | static u_char tc = 0; 97 | 98 | memset(out, 0, sizeof(out)); 99 | snprintf(tmpdirs[level], TMPDIRNAMESZ, "sort.%d.XXXXXXXXXXX", level); 100 | dir = mkdtemp(tmpdirs[level]); 101 | if (NULL == dir) 102 | errx(1, "%s", tmpdirs[level]); 103 | theLevel = level; 104 | /*fprintf(stderr, "Sorting '%s' at level %d\n", inf, theLevel); */ 105 | fprintf(stderr, "\r%c", twhiler[tc++ & 3]); 106 | in = my_pcap_open_offline(inf); 107 | pcap_layers_init(pcap_datalink(in), 0); 108 | callback_ipv4 = my_ip4_handler; 109 | callback_ipv6 = my_ip6_handler; 110 | while ((data = pcap_next(in, &hdr))) { 111 | int which = -1; 112 | handle_pcap((void *) &which, &hdr, data); 113 | assert(which != -1); 114 | if (NULL == out[which]) { 115 | char tf[128]; 116 | snprintf(tf, 128, "%s/%d.%03d.tmp", dir, getpid(), which); 117 | out[which] = my_pcap_dump_open(in, tf); 118 | } 119 | pcap_dump((void *) out[which], &hdr, data); 120 | } 121 | for (i = 0; i < N_SPLIT; i++) 122 | if (out[i]) 123 | pcap_dump_close(out[i]); 124 | 125 | /* fprintf(stderr, "Writing '%s' at level %d\n", outf, theLevel); */ 126 | pcap_out = pcap_dump_open(in, outf); 127 | my_pcap_close_offline(in); /* close 'in; after using it to open 'out' */ 128 | in = 0; 129 | for (i = 0; i < N_SPLIT; i++) { 130 | char tf[128]; 131 | if (NULL == out[i]) 132 | continue; 133 | snprintf(tf, 128, "%s/%d.%03d.tmp", dir, getpid(), i); 134 | if (level > 0) 135 | pcap_sort(tf, tf, level - 1); 136 | in = my_pcap_open_offline(tf); 137 | while ((data = pcap_next(in, &hdr))) 138 | pcap_dump((void *) pcap_out, &hdr, data); 139 | my_pcap_close_offline(in); 140 | if (0 != unlink(tf)) 141 | warn("unlink: %s", tf); 142 | } 143 | pcap_dump_close(pcap_out); 144 | if (0 != rmdir(dir)) 145 | warn("rmdir: %s", dir); 146 | tmpdirs[level][0] = '\0'; 147 | } 148 | 149 | pcap_dumper_t * 150 | spawn(int level, pcap_t * other, int *rfd) 151 | { 152 | pid_t kid; 153 | int p1[2]; /* parent -> child */ 154 | int p2[2]; /* child -> parent */ 155 | if (pipe(p1) < 0) 156 | errx(1, "pipe"); 157 | if (pipe(p2) < 0) 158 | errx(1, "pipe"); 159 | kid = fork(); 160 | if (kid < 0) 161 | errx(1, "fork"); 162 | if (0 == kid) { 163 | /* child */ 164 | int i; 165 | if (dup2(p1[0], 0) < 0) /* p->c pipe becomes c's stdin */ 166 | errx(1, "dup2"); 167 | if (dup2(p2[1], 1) < 0) /* c->p pipe becomes c's stdout */ 168 | errx(1, "dup2"); 169 | stdin = fdopen(0, "r"); /* Because pcap uses stdio!! */ 170 | stdout = fdopen(1, "w"); 171 | for (i = 3; i < 10; i++) 172 | close(i); 173 | pcap_sort("-", "-", level); 174 | exit(0); 175 | } else { 176 | /* parent */ 177 | FILE *fp1 = fdopen(p1[1], "w"); /* p->c */ 178 | pcap_dumper_t *out; 179 | if (NULL == fp1) 180 | errx(1, "fdopen"); 181 | out = pcap_dump_fopen(other, fp1); /* writing p->c */ 182 | if (NULL == out) 183 | errx(1, "pcap_dump_fopen"); 184 | close(p1[0]); 185 | close(p2[1]); 186 | *rfd = p2[0]; 187 | return out; 188 | } 189 | } 190 | 191 | uint64_t 192 | pcap_copy_fd_to_dump(int fd, pcap_dumper_t * out) 193 | { 194 | uint64_t count = 0; 195 | char errbuf[PCAP_ERRBUF_SIZE + 1]; 196 | FILE *fp = fdopen(fd, "r"); 197 | pcap_t *in; 198 | struct pcap_pkthdr hdr; 199 | const u_char *data; 200 | 201 | if (NULL == fp) 202 | errx(1, "fdopen"); 203 | in = pcap_fopen_offline(fp, errbuf); 204 | if (NULL == in) 205 | errx(1, "%s", errbuf); 206 | while ((data = pcap_next(in, &hdr))) { 207 | pcap_dump((u_char *) out, &hdr, data); 208 | count++; 209 | } 210 | my_pcap_close_offline(in); 211 | return count; 212 | } 213 | 214 | 215 | void 216 | pcap_sort_by_af_spawn(const char *inf, const char *outf) 217 | { 218 | pcap_t *in = NULL; 219 | pcap_dumper_t *out = NULL; 220 | pcap_dumper_t *v4dump = NULL; 221 | pcap_dumper_t *v6dump = NULL; 222 | int v4rfd = -1; 223 | int v6rfd = -1; 224 | struct pcap_pkthdr hdr; 225 | const u_char *data; 226 | uint64_t v4sorted = 0; 227 | uint64_t v6sorted = 0; 228 | struct timeval start; 229 | struct timeval stop; 230 | struct timeval duration; 231 | 232 | gettimeofday(&start, NULL); 233 | in = my_pcap_open_offline(inf); 234 | v4dump = spawn(3, in, &v4rfd); 235 | v6dump = spawn(15, in, &v6rfd); 236 | 237 | pcap_layers_init(pcap_datalink(in), 0); 238 | callback_ipv4 = my_ip4_af_setter; 239 | callback_ipv6 = my_ip6_af_setter; 240 | while ((data = pcap_next(in, &hdr))) { 241 | sa_family_t fam = AF_UNSPEC; 242 | handle_pcap((void *) &fam, &hdr, data); 243 | switch (fam) { 244 | case AF_INET: 245 | pcap_dump((u_char *) v4dump, &hdr, data); 246 | break; 247 | case AF_INET6: 248 | pcap_dump((u_char *) v6dump, &hdr, data); 249 | break; 250 | default: 251 | break; 252 | } 253 | } 254 | pcap_dump_close(v4dump); 255 | pcap_dump_close(v6dump); 256 | 257 | out = my_pcap_dump_open(in, outf); 258 | my_pcap_close_offline(in); 259 | v4sorted = pcap_copy_fd_to_dump(v4rfd, out); 260 | v6sorted = pcap_copy_fd_to_dump(v6rfd, out); 261 | gettimeofday(&stop, NULL); 262 | timersub(&stop, &start, &duration); 263 | fprintf(stderr, "\nSorted %" PRIu64 " IPv4 and %" PRIu64 " IPv6 packets in %d.%d seconds\n", 264 | v4sorted, v6sorted, (int) duration.tv_sec, (int) duration.tv_usec / 100000); 265 | exit(0); 266 | } 267 | 268 | int 269 | main(int argc, char *argv[]) 270 | { 271 | if (argc != 1) { 272 | fprintf(stderr, "usage: pcap-sort-by-sip < in > out\n"); 273 | exit(1); 274 | } 275 | signal(SIGHUP, cleanup); 276 | signal(SIGINT, cleanup); 277 | signal(SIGQUIT, cleanup); 278 | signal(SIGBUS, cleanup); 279 | signal(SIGSEGV, cleanup); 280 | signal(SIGPIPE, cleanup); 281 | signal(SIGTERM, cleanup); 282 | memset(tmpdirs, '\0', sizeof(tmpdirs)); 283 | pcap_sort_by_af_spawn("-", "-"); 284 | exit(0); 285 | } 286 | -------------------------------------------------------------------------------- /pcap-split.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define DEF_TIME_FMT "%s" 16 | #define DEF_COUNT_FMT "%09d.pcap" 17 | #define START_OPT 1001 18 | #define STOP_OPT 1002 19 | 20 | static const char *kick_cmd = NULL; 21 | static const char *ProgramName = "pcap-split"; 22 | static const char *gzext = ".gz"; 23 | static int opt_gzip = 0; 24 | static int opt_verbose = 0; 25 | 26 | /* Prototypes */ 27 | static void usage(const char *) __attribute__((noreturn)); 28 | static void help(void); 29 | #ifdef __linux__ 30 | extern char *strptime(const char *s, const char *format, struct tm *tm); 31 | extern int asprintf(char **strp, const char *fmt, ...); 32 | #endif 33 | 34 | int 35 | main(int argc, char *argv[]) 36 | { 37 | pcap_t *in = NULL; 38 | pcap_dumper_t *out = NULL; 39 | char errbuf[PCAP_ERRBUF_SIZE + 1]; 40 | struct pcap_pkthdr hdr; 41 | time_t this_bin; 42 | time_t last_bin = -1; 43 | time_t modulus = 0; 44 | uint64_t count = 0; 45 | uint64_t npkts = 0; 46 | const u_char *data; 47 | int ch; 48 | char *p; 49 | unsigned long ul; 50 | char *fmt = NULL; 51 | /* Track of starting and ending time */ 52 | static time_t start_time = 0; 53 | static time_t stop_time = 0; 54 | char fname[128]; 55 | char fifoname[128]; 56 | char *pcapname = fname; 57 | 58 | while ((ch = getopt(argc, argv, "?hB:E:t:n:f:k:vz")) != -1) { 59 | switch (ch) { 60 | case 't': 61 | /* Validate that is a integer */ 62 | ul = strtoul(optarg, &p, 0); 63 | if (*p != '\0') 64 | usage("argument to -t must be an integer"); 65 | modulus = (unsigned) ul; 66 | break; 67 | case 'n': 68 | if (1 != sscanf(optarg, "%" PRIu64, &count)) 69 | usage("argument to -n must be an integer"); 70 | break; 71 | case 'f': 72 | fmt = strdup(optarg); 73 | break; 74 | case 'k': 75 | kick_cmd = strdup(optarg); 76 | break; 77 | case '?': 78 | case 'h': 79 | help(); 80 | exit(0); 81 | break; 82 | case 'B': 83 | { 84 | struct tm tm; 85 | memset(&tm, '\0', sizeof(tm)); 86 | if (NULL == strptime(optarg, "%F %T", &tm)) 87 | usage("-B arg must have format YYYY-MM-DD HH:MM:SS"); 88 | start_time = timegm(&tm); 89 | } 90 | break; 91 | case 'E': 92 | { 93 | struct tm tm; 94 | memset(&tm, '\0', sizeof(tm)); 95 | if (NULL == strptime(optarg, "%F %T", &tm)) 96 | usage("-E arg must have format YYYY-MM-DD HH:MM:SS"); 97 | stop_time = timegm(&tm); 98 | } 99 | break; 100 | case 'v': 101 | opt_verbose = 1; 102 | break; 103 | case 'z': 104 | opt_gzip = 1; 105 | break; 106 | default: 107 | usage("unrecognized command line option"); 108 | } 109 | } 110 | 111 | if (0 == modulus && 0 == count) { 112 | help(); 113 | exit(1); 114 | } 115 | 116 | if (start_time && stop_time && start_time > stop_time) 117 | usage("start time must be before stop time"); 118 | 119 | /* If not format given, use the default */ 120 | if (NULL == fmt) 121 | fmt = strdup(modulus ? DEF_TIME_FMT : DEF_COUNT_FMT); 122 | 123 | in = pcap_open_offline("-", errbuf); 124 | if (NULL == in) { 125 | fprintf(stderr, "stdin: %s", errbuf); 126 | exit(1); 127 | } 128 | while ((data = pcap_next(in, &hdr))) { 129 | if (modulus) 130 | this_bin = hdr.ts.tv_sec - (hdr.ts.tv_sec % modulus); 131 | else 132 | this_bin = (time_t) (npkts++ / count); 133 | /* Check if the packet is within the time window we are 134 | * interested 135 | */ 136 | if (start_time && hdr.ts.tv_sec < start_time) 137 | continue; 138 | if (stop_time && hdr.ts.tv_sec >= stop_time) 139 | break; 140 | if (this_bin != last_bin) { 141 | if (out) { 142 | char *cmd = NULL; 143 | pcap_dump_close(out); 144 | if (opt_gzip) { 145 | int s; 146 | waitpid(-1, &s, 0); 147 | } 148 | if (kick_cmd != NULL) { 149 | if (asprintf(&cmd, "%s %s &", kick_cmd, fname) < 0) { 150 | perror("asprintf"); 151 | cmd = NULL; 152 | } else { 153 | system(cmd); 154 | free(cmd); 155 | } 156 | } 157 | } 158 | if (modulus) 159 | strftime(fname, sizeof(fname) - sizeof(gzext), fmt, gmtime(&this_bin)); 160 | else 161 | snprintf(fname, sizeof(fname) - sizeof(gzext), fmt, (int) this_bin); 162 | if (opt_gzip) { 163 | static int fifocount = 0; 164 | int gzfd = -1; 165 | strcat(fname, gzext); 166 | gzfd = open(fname, O_WRONLY | O_CREAT, 0666); 167 | if (gzfd < 0) { 168 | perror(fname); 169 | exit(1); 170 | } 171 | snprintf(fifoname, sizeof(fifoname), "/tmp/%s.fifo.%d.%d", ProgramName, (int) getpid(), fifocount++); 172 | if (mkfifo(fifoname, 0600) < 0) { 173 | perror(fifoname); 174 | exit(1); 175 | } 176 | if (0 == fork()) { 177 | /* child */ 178 | int i; 179 | close(0); 180 | if (0 != open(fifoname, O_RDONLY)) { 181 | perror(fifoname); 182 | exit(1); 183 | } 184 | if (dup2(gzfd, 1) < 0) { 185 | perror("dup2"); 186 | exit(1); 187 | } 188 | close(gzfd); 189 | for (i = 3; i < 20; i++) 190 | close(i); 191 | execlp("gzip", "gzip", "-9c", NULL); 192 | } else { 193 | close(gzfd); 194 | pcapname = fifoname; 195 | } 196 | } 197 | if (opt_verbose) 198 | fprintf(stderr, "writing %s\n", fname); 199 | out = pcap_dump_open(in, pcapname); 200 | if (opt_gzip) { 201 | /* 202 | * no race condition on unlink because open-for-write 203 | * blocks until open-for-read happens first? 204 | */ 205 | unlink(fifoname); 206 | } 207 | if (NULL == out) { 208 | perror(fname); 209 | exit(1); 210 | } 211 | last_bin = this_bin; 212 | } 213 | pcap_dump((void *) out, &hdr, data); 214 | } 215 | if (out) { 216 | char *cmd = NULL; 217 | pcap_dump_close(out); 218 | if (opt_gzip) { 219 | int s; 220 | waitpid(-1, &s, 0); 221 | } 222 | if (kick_cmd != NULL) { 223 | if (asprintf(&cmd, "%s %s &", kick_cmd, fname) < 0) { 224 | perror("asprintf"); 225 | cmd = NULL; 226 | } else { 227 | system(cmd); 228 | free(cmd); 229 | } 230 | } 231 | } 232 | exit(0); 233 | } 234 | 235 | static void 236 | usage(const char *msg) 237 | { 238 | fprintf(stderr, "%s: usage error: %s\n", ProgramName, msg); 239 | fprintf(stderr, "\n"); 240 | exit(1); 241 | } 242 | 243 | static void 244 | help(void) 245 | { 246 | fprintf(stderr, "%s\n", ProgramName); 247 | fprintf(stderr, 248 | "\noptions:\n" 249 | "\t-? or -h print these instructions and exit\n" 250 | "\t-B YYYY-MM-DD HH:MM:SS select packets starting on that date\n" 251 | "\t-E YYYY-MM-DD HH:MM:SS select packets until this time/date\n" 252 | "\t-t each seconds since\n" 253 | "\t the start time indicated by '-B'\n" 254 | "\t will close the old destination file\n" 255 | "\t and create a new one.\n" 256 | "\t-n make new output file every packets\n" 257 | "\t-f receives a format accepted by\n" 258 | "\t strftime to name the files created.\n" 259 | "\t Default %%s (UNIX timestamp)\n" 260 | "\t-k After closing an old destination\n" 261 | "\t file, will execute this command with\n" 262 | "\t the file name as first parameter\n" 263 | "\t-v produce slightly more verbose output\n" 264 | "\t-z automatcially compress each pcap\n" 265 | "\t with gzip\n"); 266 | } 267 | -------------------------------------------------------------------------------- /pcap-strip-vlans.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "pcap-tools.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #ifndef ETHERTYPE_8021Q 21 | #define ETHERTYPE_8021Q 0x8100 22 | #endif 23 | 24 | #include "pcap-tools.h" 25 | 26 | char *progname = NULL; 27 | 28 | 29 | int 30 | needs_fixing(const struct pcap_pkthdr *hdr, const u_char * data) 31 | { 32 | struct ether_header *e = (struct ether_header *) data; 33 | unsigned short etype; 34 | if (hdr->caplen < ETHER_HDR_LEN) 35 | return 0; 36 | etype = nptohs(&e->ether_type); 37 | if (ETHERTYPE_8021Q == etype) 38 | return 1; 39 | return 0; 40 | } 41 | 42 | void 43 | fix(struct pcap_pkthdr *hdr, u_char ** data) 44 | { 45 | hdr->len -= 4; 46 | hdr->caplen -= 4; 47 | *data += 4; 48 | } 49 | 50 | void 51 | usage(void) 52 | { 53 | fprintf(stderr, "usage: %s pcapfiles ...\n", progname); 54 | exit(1); 55 | } 56 | 57 | int 58 | main(int argc, char *argv[]) 59 | { 60 | pcap_t *in = NULL; 61 | pcap_dumper_t *out = NULL; 62 | struct pcap_pkthdr hdr; 63 | const u_char *data; 64 | int i; 65 | int nfixed = 0; 66 | int dryrun = 0; 67 | int dlt = 0; 68 | 69 | progname = argv[0]; 70 | while ((i = getopt(argc, argv, "n")) != -1) { 71 | switch (i) { 72 | case 'n': 73 | dryrun = 1; 74 | break; 75 | case '?': 76 | default: 77 | usage(); 78 | } 79 | } 80 | argc -= optind; 81 | argv += optind; 82 | 83 | 84 | if (argc < 1) 85 | usage(); 86 | for (i = 0; i < argc; i++) { 87 | in = my_pcap_open_offline(argv[i]); 88 | dlt = pcap_datalink(in); 89 | while ((data = pcap_next(in, &hdr))) { 90 | if (DLT_EN10MB == dlt && needs_fixing(&hdr, data)) { 91 | nfixed++; 92 | if (dryrun) 93 | warnx("found bad packet of at %10lld.%06lld", 94 | (long long int) hdr.ts.tv_sec, (long long int) hdr.ts.tv_usec); 95 | else 96 | fix(&hdr, (u_char **) & data); 97 | } 98 | if (!out) { 99 | out = pcap_dump_open(in, "-"); 100 | if (NULL == out) { 101 | perror("stdout"); 102 | exit(1); 103 | } 104 | } 105 | pcap_dump((void *) out, &hdr, data); 106 | } 107 | my_pcap_close_offline(in); 108 | } 109 | if (out) 110 | pcap_dump_close(out); 111 | fprintf(stderr, "%s: Removed %d bad packets\n", progname, nfixed); 112 | exit(0); 113 | } 114 | 115 | int 116 | is_bogus(struct pcap_pkthdr *thishdr, const u_char * thisdata) 117 | { 118 | if (thishdr->caplen > 65535) 119 | return 1; 120 | if (thishdr->len > 65535) 121 | return 1; 122 | return 0; 123 | } 124 | -------------------------------------------------------------------------------- /pcap-subtract-timestamp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int 11 | main(int argc, char *argv[]) 12 | { 13 | pcap_t *in = NULL; 14 | pcap_dumper_t *out = NULL; 15 | char errbuf[PCAP_ERRBUF_SIZE + 1]; 16 | struct pcap_pkthdr hdr; 17 | const u_char *data; 18 | char ttime[32]; 19 | struct timeval adjust; 20 | long long int L1; 21 | long long int L2; 22 | 23 | 24 | if (argc < 2) { 25 | fprintf(stderr, "usage: pcap-adjust-timestamp adjust\n"); 26 | exit(1); 27 | } 28 | 29 | snprintf(ttime, 32, "%8.6f", atof(argv[1])); 30 | if (2 != sscanf(ttime, "%lld.%lld", &L1, &L2)) { 31 | fprintf(stderr, "bad adjust time: %s\n", argv[1]); 32 | exit(1); 33 | } 34 | adjust.tv_sec = (time_t) L1; 35 | adjust.tv_usec = (time_t) L2; 36 | fprintf(stderr, "adjusting timestamps by %lld.%06lld sec\n", 37 | (long long int) adjust.tv_sec, (long long int) adjust.tv_usec); 38 | 39 | in = pcap_open_offline("-", errbuf); 40 | if (NULL == in) { 41 | fprintf(stderr, "stdin: %s", errbuf); 42 | exit(1); 43 | } 44 | out = pcap_dump_open(in, "-"); 45 | if (NULL == out) { 46 | perror("stdout"); 47 | exit(1); 48 | } 49 | while ((data = pcap_next(in, &hdr))) { 50 | struct timeval result; 51 | timersub(&hdr.ts, &adjust, &result); 52 | hdr.ts = result; 53 | pcap_dump((void *) out, &hdr, data); 54 | } 55 | pcap_close(in); 56 | if (out) 57 | pcap_dump_close(out); 58 | exit(0); 59 | } 60 | -------------------------------------------------------------------------------- /pcap-to-dlt-en10mb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include "pcap-tools.h" 18 | 19 | #ifndef ETHERTYPE_IPV6 20 | #define ETHERTYPE_IPV6 0x86dd 21 | #endif 22 | 23 | const char *progname; 24 | struct pcap_pkthdr out_hdr; 25 | u_char out_data[65536]; 26 | 27 | /* 28 | * this will only be called if 'ip' is a complete IPv header 29 | */ 30 | int 31 | my_ip4_handler(const struct ip *ip4, int len, void *userdata) 32 | { 33 | out_hdr.len = out_hdr.caplen = len + 14; 34 | htonps(&out_data[12], ETHERTYPE_IP); 35 | memcpy(&out_data[14], ip4, len); 36 | return 0; 37 | } 38 | 39 | int 40 | my_ip6_handler(const struct ip6_hdr *ip6, int len, void *userdata) 41 | { 42 | out_hdr.len = out_hdr.caplen = len + 14; 43 | htonps(&out_data[12], ETHERTYPE_IPV6); 44 | memcpy(&out_data[14], ip6, len); 45 | return 0; 46 | } 47 | 48 | int 49 | main(int argc, char *argv[]) 50 | { 51 | pcap_t *in = NULL; 52 | struct pcap_pkthdr hdr; 53 | const u_char *data; 54 | pcap_dumper_t *out = NULL; 55 | pcap_t *dead; 56 | 57 | memset(out_data, 0, sizeof(out_data)); 58 | progname = argv[0]; 59 | if (argc < 2) { 60 | fprintf(stderr, "usage: %s pcapfiles\n", progname); 61 | exit(1); 62 | } 63 | 64 | in = my_pcap_open_offline(argv[1]); 65 | dead = pcap_open_dead(DLT_EN10MB, 65536); 66 | if (NULL == dead) { 67 | perror("pcap_open_dead"); 68 | exit(1); 69 | } 70 | out = pcap_dump_open(dead, "-"); 71 | if (NULL == out) { 72 | perror("stdout"); 73 | exit(1); 74 | } 75 | pcap_layers_init(pcap_datalink(in), 0); 76 | callback_ipv4 = my_ip4_handler; 77 | callback_ipv6 = my_ip6_handler; 78 | while ((data = pcap_next(in, &hdr))) { 79 | out_hdr.ts = hdr.ts; 80 | out_hdr.len = 0; 81 | out_hdr.caplen = 0; 82 | handle_pcap(NULL, &hdr, data); 83 | if (out_hdr.len) 84 | pcap_dump((void *) out, &out_hdr, out_data); 85 | } 86 | my_pcap_close_offline(in); 87 | pcap_dump_close(out); 88 | exit(0); 89 | } 90 | -------------------------------------------------------------------------------- /pcap-to-dlt-loop.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include "pcap-tools.h" 18 | 19 | const char *progname; 20 | struct pcap_pkthdr out_hdr; 21 | const u_char *out_data; 22 | 23 | 24 | /* 25 | * this will only be called if 'ip' is a complete IPv header 26 | */ 27 | int 28 | my_ip4_handler(const struct ip *ip4, int len, void *userdata) 29 | { 30 | out_hdr.len = out_hdr.caplen = len + 4; 31 | out_data = (void *) ip4 - 4; 32 | htonpl(out_data, AF_INET); 33 | return 0; 34 | } 35 | 36 | int 37 | my_ip6_handler(const struct ip6_hdr *ip6, int len, void *userdata) 38 | { 39 | out_hdr.len = out_hdr.caplen = len + 4; 40 | out_data = (void *) ip6 - 4; 41 | htonpl(out_data, AF_INET6); 42 | return 0; 43 | } 44 | 45 | int 46 | main(int argc, char *argv[]) 47 | { 48 | pcap_t *in = NULL; 49 | struct pcap_pkthdr hdr; 50 | const u_char *data; 51 | pcap_dumper_t *out = NULL; 52 | pcap_t *dead; 53 | 54 | progname = argv[0]; 55 | if (argc < 2) { 56 | fprintf(stderr, "usage: %s pcapfiles\n", progname); 57 | exit(1); 58 | } 59 | 60 | in = my_pcap_open_offline(argv[1]); 61 | dead = pcap_open_dead(DLT_LOOP, 65536); 62 | if (NULL == dead) { 63 | perror("pcap_open_dead"); 64 | exit(1); 65 | } 66 | out = pcap_dump_open(dead, "-"); 67 | if (NULL == out) { 68 | perror("stdout"); 69 | exit(1); 70 | } 71 | pcap_layers_init(pcap_datalink(in), 0); 72 | callback_ipv4 = my_ip4_handler; 73 | callback_ipv6 = my_ip6_handler; 74 | while ((data = pcap_next(in, &hdr))) { 75 | out_hdr.ts = hdr.ts; 76 | out_hdr.len = 0; 77 | out_hdr.caplen = 0; 78 | out_data = NULL; 79 | handle_pcap(NULL, &hdr, data); 80 | if (out_data && out_hdr.len) 81 | pcap_dump((void *) out, &out_hdr, out_data); 82 | } 83 | my_pcap_close_offline(in); 84 | pcap_dump_close(out); 85 | exit(0); 86 | } 87 | -------------------------------------------------------------------------------- /pcap-to-dlt-raw.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "pcap-tools.h" 17 | #include "pcap_layers.h" 18 | 19 | const char *progname; 20 | struct pcap_pkthdr out_hdr; 21 | const u_char *out_data; 22 | 23 | /* 24 | * this will only be called if 'ip' is a complete IPv header 25 | */ 26 | int 27 | my_ip4_handler(const struct ip *ip4, int len, void *userdata) 28 | { 29 | out_hdr.caplen = len; 30 | out_data = (void *) ip4; 31 | return 0; 32 | } 33 | 34 | int 35 | my_ip6_handler(const struct ip6_hdr *ip6, int len, void *userdata) 36 | { 37 | out_hdr.caplen = len; 38 | out_data = (void *) ip6; 39 | return 0; 40 | } 41 | 42 | int 43 | main(int argc, char *argv[]) 44 | { 45 | pcap_t *in = NULL; 46 | struct pcap_pkthdr in_hdr; 47 | const u_char *data; 48 | pcap_dumper_t *out = NULL; 49 | pcap_t *dead; 50 | 51 | progname = argv[0]; 52 | if (argc < 2) { 53 | fprintf(stderr, "usage: %s pcapfiles\n", progname); 54 | exit(1); 55 | } 56 | 57 | in = my_pcap_open_offline(argv[1]); 58 | dead = pcap_open_dead(DLT_RAW, 65536); 59 | if (NULL == dead) { 60 | perror("pcap_open_dead"); 61 | exit(1); 62 | } 63 | out = pcap_dump_open(dead, "-"); 64 | if (NULL == out) { 65 | perror("stdout"); 66 | exit(1); 67 | } 68 | pcap_layers_init(pcap_datalink(in), 0); 69 | callback_ipv4 = my_ip4_handler; 70 | callback_ipv6 = my_ip6_handler; 71 | while ((data = pcap_next(in, &in_hdr))) { 72 | out_hdr.ts = in_hdr.ts; 73 | out_hdr.caplen = 0; 74 | out_data = NULL; 75 | if (in_hdr.caplen > in_hdr.len) 76 | in_hdr.caplen = in_hdr.len; 77 | handle_pcap(NULL, &in_hdr, data); 78 | if (out_data && out_hdr.caplen) { 79 | out_hdr.len = in_hdr.len + out_hdr.caplen - in_hdr.caplen; 80 | #if DEBUG 81 | fprintf(stderr, "in len %d in caplen %d out len %d out caplen %d\n", 82 | in_hdr.len, in_hdr.caplen, out_hdr.len, out_hdr.caplen); 83 | #endif 84 | pcap_dump((void *) out, &out_hdr, out_data); 85 | } 86 | } 87 | my_pcap_close_offline(in); 88 | pcap_dump_close(out); 89 | exit(0); 90 | } 91 | -------------------------------------------------------------------------------- /pcap-tools.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | pcap_t * 12 | my_pcap_open_offline(const char *pcapfile) 13 | { 14 | char errbuf[PCAP_ERRBUF_SIZE + 1]; 15 | char fifoname[256]; 16 | int waitstatus; 17 | const char *readfile = pcapfile; 18 | fifoname[0] = '\0'; 19 | static unsigned int fifocount = 0; 20 | pcap_t *in; 21 | assert(pcapfile); 22 | if (pcapfile[0] == '|') { 23 | char **args = 0; 24 | const char *s; 25 | unsigned int nargs = 0; 26 | unsigned int i = 0; 27 | /* count arguments */ 28 | nargs++; /* first arg */ 29 | for (s = pcapfile; *s; s++) { 30 | if (*s == ' ') 31 | nargs++; 32 | } 33 | nargs++; /* terminating null */ 34 | args = calloc(nargs, sizeof(char *)); 35 | args[0] = strtok((char *) pcapfile + 1, " "); 36 | for (i = 1; i < nargs - 1; i++) { 37 | args[i] = strtok(NULL, " "); 38 | assert(args[i]); 39 | } 40 | snprintf(fifoname, 256, "/tmp/fifo.%d.%u", getpid(), fifocount++); 41 | mkfifo(fifoname, 0600); 42 | if (0 == fork()) { 43 | close(1); 44 | open(fifoname, O_WRONLY); 45 | execvp(args[0], args); 46 | perror(args[0]); 47 | abort(); 48 | } 49 | readfile = fifoname; 50 | } else if (0 == strcmp(pcapfile + strlen(pcapfile) - 3, ".gz")) { 51 | snprintf(fifoname, 256, "/tmp/fifo.%d.%u", getpid(), fifocount++); 52 | mkfifo(fifoname, 0600); 53 | if (0 == fork()) { 54 | close(1); 55 | open(fifoname, O_WRONLY); 56 | execlp("gzip", "gzip", "-dc", pcapfile, NULL); 57 | perror("gzip"); 58 | abort(); 59 | } 60 | readfile = fifoname; 61 | } else if (0 == strcmp(pcapfile + strlen(pcapfile) - 4, ".bz2")) { 62 | snprintf(fifoname, 256, "/tmp/fifo.%d.%u", getpid(), fifocount++); 63 | mkfifo(fifoname, 0600); 64 | if (0 == fork()) { 65 | close(1); 66 | open(fifoname, O_WRONLY); 67 | execlp("bzip2", "bzip2", "-dc", pcapfile, NULL); 68 | perror("bzip2"); 69 | abort(); 70 | } 71 | readfile = fifoname; 72 | } else if (0 == strcmp(pcapfile + strlen(pcapfile) - 3, ".xz")) { 73 | snprintf(fifoname, 256, "/tmp/fifo.%d.%u", getpid(), fifocount++); 74 | mkfifo(fifoname, 0600); 75 | if (0 == fork()) { 76 | close(1); 77 | open(fifoname, O_WRONLY); 78 | execlp("xz", "xz", "-dc", pcapfile, NULL); 79 | perror("xz"); 80 | abort(); 81 | } 82 | readfile = fifoname; 83 | } 84 | in = pcap_open_offline(readfile, errbuf); 85 | if (fifoname[0]) 86 | unlink(fifoname); 87 | if (NULL == in && fifoname[0]) { 88 | waitpid(-1, &waitstatus, 0); 89 | return 0; 90 | } 91 | if (NULL == in) 92 | errx(1, "[%d] %s(%d) %s: %s", getpid(), __FILE__, __LINE__, pcapfile, errbuf); 93 | return in; 94 | } 95 | 96 | void 97 | my_pcap_close_offline(pcap_t * in) 98 | { 99 | int waitstatus; 100 | pcap_close(in); 101 | waitpid(-1, &waitstatus, 0); 102 | } 103 | -------------------------------------------------------------------------------- /pcap-tools.h: -------------------------------------------------------------------------------- 1 | #ifndef PCAP_TOOLS_H 2 | #define PCAP_TOOLS_H 1 3 | 4 | /* Convert the network order 32 bit integer pointed to by p to host order. 5 | * p does not have to be aligned. */ 6 | #ifndef nptohl 7 | #define nptohl(p) \ 8 | ((((uint8_t*)(p))[0] << 24) | \ 9 | (((uint8_t*)(p))[1] << 16) | \ 10 | (((uint8_t*)(p))[2] << 8) | \ 11 | ((uint8_t*)(p))[3]) 12 | #endif 13 | 14 | /* Copy the host order 32 bit integer in x into the memory pointed to by p 15 | * in network order. p does not have to be aligned. */ 16 | #ifndef htonpl 17 | #define htonpl(p, x) \ 18 | do { \ 19 | ((uint8_t*)(p))[0] = (x & 0xFF000000) >> 24; \ 20 | ((uint8_t*)(p))[1] = (x & 0x00FF0000) >> 16; \ 21 | ((uint8_t*)(p))[2] = (x & 0x0000FF00) >> 8; \ 22 | ((uint8_t*)(p))[3] = (x & 0x000000FF) >> 0; \ 23 | } while (0) 24 | #endif 25 | 26 | /* Convert the network order 16 bit integer pointed to by p to host order. 27 | * p does not have to be aligned. */ 28 | #ifndef nptohs 29 | #define nptohs(p) \ 30 | ((((uint8_t*)(p))[0] << 8) | ((uint8_t*)(p))[1]) 31 | #endif 32 | 33 | /* Copy the host order 16 bit integer in x into the memory pointed to by p 34 | * in network order. p does not have to be aligned. */ 35 | #ifndef htonps 36 | #define htonps(p, x) \ 37 | do { \ 38 | ((uint8_t*)(p))[0] = (x & 0xFF00) >> 8; \ 39 | ((uint8_t*)(p))[1] = (x & 0x00FF) >> 0; \ 40 | } while (0) 41 | #endif 42 | 43 | pcap_t * my_pcap_open_offline(const char *pcapfile); 44 | void my_pcap_close_offline(pcap_t *in); 45 | 46 | #endif /* PCAP_TOOLS_H */ 47 | --------------------------------------------------------------------------------