1/* 2 Unix SMB/CIFS implementation. 3 Utility to extract pcap files from samba (log level 10) log files 4 5 Copyright (C) Jelmer Vernooij 2003 6 Thanks to Tim Potter for the genial idea 7 8 Portions (from capconvert.c) (C) Andrew Tridgell 1997 9 Portions (from text2pcap.c) (C) Ashok Narayanan 2001 10 11 Example use with -h parameter: 12 log2pcaphex < samba-log-file | text2pcap -T 139,139 - foo.pcap 13 14 TODO: Have correct IP and TCP checksums. 15 16 This program is free software; you can redistribute it and/or modify 17 it under the terms of the GNU General Public License as published by 18 the Free Software Foundation; either version 2 of the License, or 19 (at your option) any later version. 20 21 This program is distributed in the hope that it will be useful, 22 but WITHOUT ANY WARRANTY; without even the implied warranty of 23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 GNU General Public License for more details. 25 26 You should have received a copy of the GNU General Public License 27 along with this program; if not, write to the Free Software 28 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 29*/ 30 31#include "includes.h" 32#include <assert.h> 33 34int quiet = 0; 35int hexformat = 0; 36 37#define itoa(a) ((a) < 0xa?'0'+(a):'A' + (a-0xa)) 38 39#include <stdlib.h> 40#include <unistd.h> 41#include <sys/time.h> 42#include <stdio.h> 43#include <fcntl.h> 44 45#define TCPDUMP_MAGIC 0xa1b2c3d4 46 47/* tcpdump file format */ 48struct tcpdump_file_header { 49 uint32 magic; 50 uint16 major; 51 uint16 minor; 52 int32 zone; 53 uint32 sigfigs; 54 uint32 snaplen; 55 uint32 linktype; 56}; 57 58struct tcpdump_packet { 59 struct timeval ts; 60 uint32 caplen; 61 uint32 len; 62}; 63 64typedef struct { 65 uint8 ver_hdrlen; 66 uint8 dscp; 67 uint16 packet_length; 68 uint16 identification; 69 uint8 flags; 70 uint8 fragment; 71 uint8 ttl; 72 uint8 protocol; 73 uint16 hdr_checksum; 74 uint32 src_addr; 75 uint32 dest_addr; 76} hdr_ip_t; 77 78static hdr_ip_t HDR_IP = {0x45, 0, 0, 0x3412, 0, 0, 0xff, 6, 0, 0x01010101, 0x02020202}; 79 80typedef struct { 81 uint16 source_port; 82 uint16 dest_port; 83 uint32 seq_num; 84 uint32 ack_num; 85 uint8 hdr_length; 86 uint8 flags; 87 uint16 window; 88 uint16 checksum; 89 uint16 urg; 90} hdr_tcp_t; 91 92static hdr_tcp_t HDR_TCP = {139, 139, 0, 0, 0x50, 0, 0, 0, 0}; 93 94void print_pcap_header(FILE *out) 95{ 96 struct tcpdump_file_header h; 97 h.magic = TCPDUMP_MAGIC; 98 h.major = 2; 99 h.minor = 4; 100 h.zone = 0; 101 h.sigfigs = 0; 102 h.snaplen = 102400; /* As long packets as possible */ 103 h.linktype = 101; /* Raw IP */ 104 fwrite(&h, sizeof(struct tcpdump_file_header), 1, out); 105} 106 107void print_pcap_packet(FILE *out, unsigned char *data, long length, long caplen) 108{ 109 static int i = 0; 110 struct tcpdump_packet p; 111 i++; 112 p.ts.tv_usec = 0; 113 p.ts.tv_sec = 0; 114 p.caplen = caplen; 115 p.len = length; 116 fwrite(&p, sizeof(struct tcpdump_packet), 1, out); 117 fwrite(data, sizeof(unsigned char), caplen, out); 118} 119 120void print_hex_packet(FILE *out, unsigned char *data, long length) 121{ 122 long i,cur = 0; 123 while(cur < length) { 124 fprintf(out, "%06lX ", cur); 125 for(i = cur; i < length && i < cur + 16; i++) { 126 fprintf(out, "%02x ", data[i]); 127 } 128 129 cur = i; 130 fprintf(out, "\n"); 131 } 132} 133 134void print_netbios_packet(FILE *out, unsigned char *data, long length, long actual_length) 135{ 136 unsigned char *newdata; long offset = 0; 137 long newlen; 138 139 newlen = length+sizeof(HDR_IP)+sizeof(HDR_TCP); 140 newdata = malloc(newlen); 141 142 HDR_IP.packet_length = htons(newlen); 143 HDR_TCP.window = htons(0x2000); 144 HDR_TCP.source_port = HDR_TCP.dest_port = htons(139); 145 146 memcpy(newdata+offset, &HDR_IP, sizeof(HDR_IP));offset+=sizeof(HDR_IP); 147 memcpy(newdata+offset, &HDR_TCP, sizeof(HDR_TCP));offset+=sizeof(HDR_TCP); 148 memcpy(newdata+offset,data,length); 149 150 print_pcap_packet(out, newdata, newlen, actual_length+offset); 151 free(newdata); 152} 153 154unsigned char *curpacket = NULL; 155long curpacket_len = 0; 156 157void read_log_msg(FILE *in, unsigned char **_buffer, long *buffersize, long *data_offset, long *data_length) 158{ 159 unsigned char *buffer; 160 int tmp; long i; 161 assert(fscanf(in, " size=%ld\n", buffersize)); 162 *buffersize+=4; /* for netbios */ 163 buffer = malloc(*buffersize); 164 memset(buffer, 0, *buffersize); 165 /* NetBIOS */ 166 buffer[0] = 0x00; 167 buffer[1] = 0x00; 168 memcpy(buffer+2, &buffersize, 2); 169 buffer[4] = 0xFF; 170 buffer[5] = 'S'; 171 buffer[6] = 'M'; 172 buffer[7] = 'B'; 173 assert(fscanf(in, " smb_com=0x%x\n", &tmp)); buffer[smb_com] = tmp; 174 assert(fscanf(in, " smb_rcls=%d\n", &tmp)); buffer[smb_rcls] = tmp; 175 assert(fscanf(in, " smb_reh=%d\n", &tmp)); buffer[smb_reh] = tmp; 176 assert(fscanf(in, " smb_err=%d\n", &tmp)); memcpy(buffer+smb_err, &tmp, 2); 177 assert(fscanf(in, " smb_flg=%d\n", &tmp)); buffer[smb_flg] = tmp; 178 assert(fscanf(in, " smb_flg2=%d\n", &tmp)); memcpy(buffer+smb_flg2, &tmp, 2); 179 assert(fscanf(in, " smb_tid=%d\n", &tmp)); memcpy(buffer+smb_tid, &tmp, 2); 180 assert(fscanf(in, " smb_pid=%d\n", &tmp)); memcpy(buffer+smb_pid, &tmp, 2); 181 assert(fscanf(in, " smb_uid=%d\n", &tmp)); memcpy(buffer+smb_uid, &tmp, 2); 182 assert(fscanf(in, " smb_mid=%d\n", &tmp)); memcpy(buffer+smb_mid, &tmp, 2); 183 assert(fscanf(in, " smt_wct=%d\n", &tmp)); buffer[smb_wct] = tmp; 184 for(i = 0; i < buffer[smb_wct]; i++) { 185 assert(fscanf(in, " smb_vwv[%*2d]=%*5d (0x%X)\n", &tmp)); 186 memcpy(buffer+smb_vwv+i*2, &tmp, 2); 187 } 188 189 *data_offset = smb_vwv+buffer[smb_wct]*2; 190 assert(fscanf(in, " smb_bcc=%ld\n", data_length)); buffer[(*data_offset)] = *data_length; 191 (*data_offset)+=2; 192 *_buffer = buffer; 193} 194 195long read_log_data(FILE *in, unsigned char *buffer, long data_length) 196{ 197 long i, addr; char real[2][16]; int ret; 198 unsigned char tmp; 199 for(i = 0; i < data_length; i++) { 200 if(i % 16 == 0){ 201 if(i != 0) { /* Read data after each line */ 202 assert(fscanf(in, "%8s %8s", real[0], real[1]) == 2); 203 } 204 ret = fscanf(in, " [%03lX]", &addr); 205 if(!ret) { 206 if(!quiet)fprintf(stderr, "Only first %ld bytes are logged, packet trace will be incomplete\nTry a higher log level\n", i); 207 return i-1; 208 } 209 assert(addr == i); 210 } 211 if(!fscanf(in, "%02lX", &tmp)) { 212 if(!quiet)fprintf(stderr, "Only first %ld bytes are logged, packet trace will be incomplete\nTry a higher log level\n", i-1); 213 return i-1; 214 } 215 buffer[i] = tmp; 216 } 217 return data_length; 218} 219 220int main (int argc, char **argv) 221{ 222 const char *infile, *outfile; 223 FILE *out, *in; 224 int opt; 225 poptContext pc; 226 char buffer[4096]; 227 long data_offset, data_length; 228 long data_bytes_read; 229 int in_packet = 0; 230 struct poptOption long_options[] = { 231 POPT_AUTOHELP 232 { "quiet", 'q', POPT_ARG_NONE, &quiet, 0, "Be quiet, don't output warnings" }, 233 { "hex", 'h', POPT_ARG_NONE, &hexformat, 0, "Output format readable by text2pcap" }, 234 POPT_TABLEEND 235 }; 236 237 pc = poptGetContext(NULL, argc, (const char **) argv, long_options, 238 POPT_CONTEXT_KEEP_FIRST); 239 poptSetOtherOptionHelp(pc, "[<infile> [<outfile>]]"); 240 241 242 while((opt = poptGetNextOpt(pc)) != -1) { 243 switch (opt) { 244 } 245 } 246 247 poptGetArg(pc); /* Drop argv[0], the program name */ 248 249 infile = poptGetArg(pc); 250 251 if(infile) { 252 in = fopen(infile, "r"); 253 if(!in) { 254 perror("fopen"); 255 return 1; 256 } 257 } else in = stdin; 258 259 outfile = poptGetArg(pc); 260 261 if(outfile) { 262 out = fopen(outfile, "w+"); 263 if(!out) { 264 perror("fopen"); 265 fprintf(stderr, "Can't find %s, using stdout...\n", outfile); 266 } 267 } 268 269 if(!outfile) out = stdout; 270 271 if(!hexformat)print_pcap_header(out); 272 273 while(!feof(in)) { 274 fgets(buffer, sizeof(buffer), in); 275 if(buffer[0] == '[') { /* Header */ 276 if(strstr(buffer, "show_msg")) { 277 in_packet++; 278 if(in_packet == 1)continue; 279 read_log_msg(in, &curpacket, &curpacket_len, &data_offset, &data_length); 280 } else if(in_packet && strstr(buffer, "dump_data")) { 281 data_bytes_read = read_log_data(in, curpacket+data_offset, data_length); 282 } else { 283 if(in_packet){ 284 if(hexformat) print_hex_packet(out, curpacket, curpacket_len); 285 else print_netbios_packet(out, curpacket, curpacket_len, data_bytes_read+data_offset); 286 free(curpacket); 287 } 288 in_packet = 0; 289 } 290 } 291 } 292 293 return 0; 294} 295