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: 12 Output NBSS(SMB) packets in hex and convert to pcap adding 13 Eth/IP/TCP headers 14 15 log2pcap -h < samba.log | text2pcap -T 139,139 - samba.pcap 16 17 Output directly to pcap format without Eth headers or TCP 18 sequence numbers 19 20 log2pcap samba.log samba.pcap 21 22 TODO: 23 - Hex to text2pcap outputs are not properly parsed in Wireshark 24 the NBSS or SMB level. This is a bug. 25 - Writing directly to pcap format doesn't include sequence numbers 26 in the TCP packets 27 - Check if a packet is a response or request and set IP to/from 28 addresses accordingly. Currently all packets come from the same 29 dummy IP and go to the same dummy IP 30 - Add a message when done parsing about the number of pacekts 31 processed 32 - Parse NBSS packet header data from log file 33 - Have correct IP and TCP checksums. 34 35 Warning: 36 Samba log level 10 outputs a max of 512 bytes from the packet data 37 section. Packets larger than this will be truncated. 38 39 This program is free software; you can redistribute it and/or modify 40 it under the terms of the GNU General Public License as published by 41 the Free Software Foundation; either version 3 of the License, or 42 (at your option) any later version. 43 44 This program is distributed in the hope that it will be useful, 45 but WITHOUT ANY WARRANTY; without even the implied warranty of 46 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 47 GNU General Public License for more details. 48 49 You should have received a copy of the GNU General Public License 50 along with this program. If not, see <http://www.gnu.org/licenses/>. 51*/ 52 53#include "includes.h" 54 55/* We don't care about the paranoid malloc checker in this standalone 56 program */ 57#undef malloc 58 59#include <assert.h> 60 61int quiet = 0; 62int hexformat = 0; 63 64#define itoa(a) ((a) < 0xa?'0'+(a):'A' + (a-0xa)) 65 66#include <stdlib.h> 67#include <unistd.h> 68#include <sys/time.h> 69#include <stdio.h> 70#include <fcntl.h> 71 72#define TCPDUMP_MAGIC 0xa1b2c3d4 73 74/* tcpdump file format */ 75struct tcpdump_file_header { 76 uint32 magic; 77 uint16 major; 78 uint16 minor; 79 int32 zone; 80 uint32 sigfigs; 81 uint32 snaplen; 82 uint32 linktype; 83}; 84 85struct tcpdump_packet { 86 struct timeval ts; 87 uint32 caplen; 88 uint32 len; 89}; 90 91typedef struct { 92 uint8 ver_hdrlen; 93 uint8 dscp; 94 uint16 packet_length; 95 uint16 identification; 96 uint8 flags; 97 uint8 fragment; 98 uint8 ttl; 99 uint8 protocol; 100 uint16 hdr_checksum; 101 uint32 src_addr; 102 uint32 dest_addr; 103} hdr_ip_t; 104 105static hdr_ip_t HDR_IP = {0x45, 0, 0, 0x3412, 0, 0, 0xff, 6, 0, 0x01010101, 0x02020202}; 106 107typedef struct { 108 uint16 source_port; 109 uint16 dest_port; 110 uint32 seq_num; 111 uint32 ack_num; 112 uint8 hdr_length; 113 uint8 flags; 114 uint16 window; 115 uint16 checksum; 116 uint16 urg; 117} hdr_tcp_t; 118 119static hdr_tcp_t HDR_TCP = {139, 139, 0, 0, 0x50, 0, 0, 0, 0}; 120 121static void print_pcap_header(FILE *out) 122{ 123 struct tcpdump_file_header h; 124 h.magic = TCPDUMP_MAGIC; 125 h.major = 2; 126 h.minor = 4; 127 h.zone = 0; 128 h.sigfigs = 0; 129 h.snaplen = 102400; /* As long packets as possible */ 130 h.linktype = 101; /* Raw IP */ 131 fwrite(&h, sizeof(struct tcpdump_file_header), 1, out); 132} 133 134static void print_pcap_packet(FILE *out, unsigned char *data, long length, 135 long caplen) 136{ 137 static int i = 0; 138 struct tcpdump_packet p; 139 i++; 140 p.ts.tv_usec = 0; 141 p.ts.tv_sec = 0; 142 p.caplen = caplen; 143 p.len = length; 144 fwrite(&p, sizeof(struct tcpdump_packet), 1, out); 145 fwrite(data, sizeof(unsigned char), caplen, out); 146} 147 148static void print_hex_packet(FILE *out, unsigned char *data, long length) 149{ 150 long i,cur = 0; 151 while(cur < length) { 152 fprintf(out, "%06lX ", cur); 153 for(i = cur; i < length && i < cur + 16; i++) { 154 fprintf(out, "%02x ", data[i]); 155 } 156 157 cur = i; 158 fprintf(out, "\n"); 159 } 160} 161 162static void print_netbios_packet(FILE *out, unsigned char *data, long length, 163 long actual_length) 164{ 165 unsigned char *newdata; long offset = 0; 166 long newlen; 167 168 newlen = length+sizeof(HDR_IP)+sizeof(HDR_TCP); 169 newdata = (unsigned char *)malloc(newlen); 170 171 HDR_IP.packet_length = htons(newlen); 172 HDR_TCP.window = htons(0x2000); 173 HDR_TCP.source_port = HDR_TCP.dest_port = htons(139); 174 175 memcpy(newdata+offset, &HDR_IP, sizeof(HDR_IP));offset+=sizeof(HDR_IP); 176 memcpy(newdata+offset, &HDR_TCP, sizeof(HDR_TCP));offset+=sizeof(HDR_TCP); 177 memcpy(newdata+offset,data,length); 178 179 print_pcap_packet(out, newdata, newlen, actual_length+offset); 180 free(newdata); 181} 182 183unsigned char *curpacket = NULL; 184unsigned short curpacket_len = 0; 185long line_num = 0; 186 187/* Read the log message produced by lib/util.c:show_msg() containing the: 188 * SMB_HEADER 189 * SMB_PARAMETERS 190 * SMB_DATA.ByteCount 191 * 192 * Example: 193 * [2007/04/08 20:41:39, 5] lib/util.c:show_msg(516) 194 * size=144 195 * smb_com=0x73 196 * smb_rcls=0 197 * smb_reh=0 198 * smb_err=0 199 * smb_flg=136 200 * smb_flg2=49153 201 * smb_tid=1 202 * smb_pid=65279 203 * smb_uid=0 204 * smb_mid=64 205 * smt_wct=3 206 * smb_vwv[ 0]= 117 (0x75) 207 * smb_vwv[ 1]= 128 (0x80) 208 * smb_vwv[ 2]= 1 (0x1) 209 * smb_bcc=87 210 */ 211static void read_log_msg(FILE *in, unsigned char **_buffer, 212 unsigned short *buffersize, long *data_offset, 213 long *data_length) 214{ 215 unsigned char *buffer; 216 int tmp; long i; 217 assert(fscanf(in, " size=%hu\n", buffersize)); line_num++; 218 buffer = (unsigned char *)malloc(*buffersize+4); /* +4 for NBSS Header */ 219 memset(buffer, 0, *buffersize+4); 220 /* NetBIOS Session Service */ 221 buffer[0] = 0x00; 222 buffer[1] = 0x00; 223 memcpy(buffer+2, &buffersize, 2); /* TODO: need to copy as little-endian regardless of platform */ 224 /* SMB Packet */ 225 buffer[4] = 0xFF; 226 buffer[5] = 'S'; 227 buffer[6] = 'M'; 228 buffer[7] = 'B'; 229 assert(fscanf(in, " smb_com=0x%x\n", &tmp)); buffer[smb_com] = tmp; line_num++; 230 assert(fscanf(in, " smb_rcls=%d\n", &tmp)); buffer[smb_rcls] = tmp; line_num++; 231 assert(fscanf(in, " smb_reh=%d\n", &tmp)); buffer[smb_reh] = tmp; line_num++; 232 assert(fscanf(in, " smb_err=%d\n", &tmp)); memcpy(buffer+smb_err, &tmp, 2); line_num++; 233 assert(fscanf(in, " smb_flg=%d\n", &tmp)); buffer[smb_flg] = tmp; line_num++; 234 assert(fscanf(in, " smb_flg2=%d\n", &tmp)); memcpy(buffer+smb_flg2, &tmp, 2); line_num++; 235 assert(fscanf(in, " smb_tid=%d\n", &tmp)); memcpy(buffer+smb_tid, &tmp, 2); line_num++; 236 assert(fscanf(in, " smb_pid=%d\n", &tmp)); memcpy(buffer+smb_pid, &tmp, 2); line_num++; 237 assert(fscanf(in, " smb_uid=%d\n", &tmp)); memcpy(buffer+smb_uid, &tmp, 2); line_num++; 238 assert(fscanf(in, " smb_mid=%d\n", &tmp)); memcpy(buffer+smb_mid, &tmp, 2); line_num++; 239 assert(fscanf(in, " smt_wct=%d\n", &tmp)); buffer[smb_wct] = tmp; line_num++; 240 for(i = 0; i < buffer[smb_wct]; i++) { 241 assert(fscanf(in, " smb_vwv[%*3d]=%*5d (0x%X)\n", &tmp)); line_num++; 242 memcpy(buffer+smb_vwv+i*2, &tmp, 2); 243 } 244 245 *data_offset = smb_vwv+buffer[smb_wct]*2; 246 assert(fscanf(in, " smb_bcc=%ld\n", data_length)); buffer[(*data_offset)] = *data_length; line_num++; 247 (*data_offset)+=2; 248 *_buffer = buffer; 249} 250 251/* Read the log message produced by lib/util.c:dump_data() containing: 252 * SMB_DATA.Bytes 253 * 254 * Example: 255 * [2007/04/08 20:41:39, 10] lib/util.c:dump_data(2243) 256 * [000] 00 55 00 6E 00 69 00 78 00 00 00 53 00 61 00 6D .U.n.i.x ...S.a.m 257 * [010] 00 62 00 61 00 20 00 33 00 2E 00 30 00 2E 00 32 .b.a. .3 ...0...2 258 * [020] 00 34 00 2D 00 49 00 73 00 69 00 6C 00 6F 00 6E .4.-.I.s .i.l.o.n 259 * [030] 00 20 00 4F 00 6E 00 65 00 46 00 53 00 20 00 76 . .O.n.e .F.S. .v 260 * [040] 00 34 00 2E 00 30 00 00 00 49 00 53 00 49 00 4C .4...0.. .I.S.I.L 261 * [050] 00 4F 00 4E 00 00 00 .O.N... 262 */ 263static long read_log_data(FILE *in, unsigned char *buffer, long data_length) 264{ 265 long i, addr; char real[2][16]; int ret; 266 unsigned int tmp; 267 for(i = 0; i < data_length; i++) { 268 if(i % 16 == 0){ 269 if(i != 0) { 270 /* Read and discard the ascii data after each line. */ 271 assert(fscanf(in, " %8c %8c\n", real[0], real[1]) == 2); 272 } 273 ret = fscanf(in, " [%03lX]", &addr); line_num++; 274 if(!ret) { 275 if(!quiet) 276 fprintf(stderr, "%ld: Only first %ld bytes are logged, " 277 "packet trace will be incomplete\n", line_num, i-1); 278 return i-1; 279 } 280 assert(addr == i); 281 } 282 if(!fscanf(in, "%02X", &tmp)) { 283 if(!quiet) 284 fprintf(stderr, "%ld: Log message formated incorrectly. " 285 "Only first %ld bytes are logged, packet trace will " 286 "be incomplete\n", line_num, i-1); 287 while ((tmp = getc(in)) != '\n'); 288 return i-1; 289 } 290 buffer[i] = tmp; 291 } 292 293 /* Consume the newline so we don't increment num_lines twice */ 294 while ((tmp = getc(in)) != '\n'); 295 return data_length; 296} 297 298int main (int argc, char **argv) 299{ 300 const char *infile, *outfile; 301 FILE *out, *in; 302 int opt; 303 poptContext pc; 304 char buffer[4096]; 305 long data_offset, data_length; 306 long data_bytes_read = 0; 307 int in_packet = 0; 308 struct poptOption long_options[] = { 309 POPT_AUTOHELP 310 { "quiet", 'q', POPT_ARG_NONE, &quiet, 0, "Be quiet, don't output warnings" }, 311 { "hex", 'h', POPT_ARG_NONE, &hexformat, 0, "Output format readable by text2pcap" }, 312 POPT_TABLEEND 313 }; 314 315 pc = poptGetContext(NULL, argc, (const char **) argv, long_options, 316 POPT_CONTEXT_KEEP_FIRST); 317 poptSetOtherOptionHelp(pc, "[<infile> [<outfile>]]"); 318 319 320 while((opt = poptGetNextOpt(pc)) != -1) { 321 switch (opt) { 322 } 323 } 324 325 poptGetArg(pc); /* Drop argv[0], the program name */ 326 327 infile = poptGetArg(pc); 328 329 if(infile) { 330 in = fopen(infile, "r"); 331 if(!in) { 332 perror("fopen"); 333 return 1; 334 } 335 } else in = stdin; 336 337 outfile = poptGetArg(pc); 338 339 if(outfile) { 340 out = fopen(outfile, "w+"); 341 if(!out) { 342 perror("fopen"); 343 fprintf(stderr, "Can't find %s, using stdout...\n", outfile); 344 return 1; 345 } 346 } 347 348 if(!outfile) out = stdout; 349 350 if(!hexformat)print_pcap_header(out); 351 352 while(!feof(in)) { 353 fgets(buffer, sizeof(buffer), in); line_num++; 354 if(buffer[0] == '[') { /* Header */ 355 if(strstr(buffer, "show_msg")) { 356 in_packet++; 357 if(in_packet == 1)continue; 358 read_log_msg(in, &curpacket, &curpacket_len, &data_offset, &data_length); 359 } else if(in_packet && strstr(buffer, "dump_data")) { 360 data_bytes_read = read_log_data(in, curpacket+data_offset, data_length); 361 } else { 362 if(in_packet){ 363 if(hexformat) print_hex_packet(out, curpacket, curpacket_len); 364 else print_netbios_packet(out, curpacket, curpacket_len, data_bytes_read+data_offset); 365 free(curpacket); 366 } 367 in_packet = 0; 368 } 369 } 370 } 371 372 if (in != stdin) { 373 fclose(in); 374 } 375 376 if (out != stdout) { 377 fclose(out); 378 } 379 380 return 0; 381} 382