/*************************************************************************** * Test the banner1 detection system by throwing random frames at it ***************************************************************************/ void banner1_test(const char *filename) { struct PcapFile *cap; unsigned link_type; cap = pcapfile_openread(filename); if (cap == NULL) { fprintf(stderr, "%s: can't open capture file\n", filename); return; } link_type = pcapfile_datalink(cap); for (;;) { int packets_read; unsigned secs; unsigned usecs; unsigned origlength; unsigned length; unsigned char px[65536]; struct PreprocessedInfo parsed; unsigned x; packets_read = pcapfile_readframe( cap, /* capture dump file */ &secs, &usecs, &origlength, &length, px, sizeof(px)); if (packets_read == 0) break; x = preprocess_frame(px, length, link_type, &parsed); if (x == 0) continue; } pcapfile_close(cap); }
int pcap2zone(int argc, char *argv[]) { struct Pcap2Zone pcap2zone[1]; struct Catalog *catalog; int i; /* * Create a catalog/database */ catalog = catalog_create(); pcap2zone->db = catalog; /* * Initialize it with a pseudo-SOA record for the root zone */ { static const struct DomainPointer root = {(const unsigned char*)"\0",1}; struct ZoneFileParser *parser; parser = zonefile_begin( root, /* origin */ 60, /* TTL */ 10000, /* filesize */ "<pcap2zone>", /* filename */ zonefile_load, /* callback */ catalog /* callback data */ ); LOAD("$TTL 60\r\n" "@ IN SOA ns hostmaster (\r\n" " 2003080800 ; sn = serial number\r\n" " 172800 ; ref = refresh = 2d\r\n" " 15m ; ret = update retry = 15m\r\n" " 1209600 ; ex = expiry = 2w\r\n" " 1H ; nx = nxdomain ttl = 1h\r\n" " )\r\n", parser); zonefile_end(parser); } for (i=2; i<argc; i++) { const char *filename = argv[i]; struct Tracker tracker[1]; struct PcapFile *p; //uint64_t filesize; memset(tracker, 0, sizeof(tracker[0])); //filesize = tracker_get_filesize(tracker, filename); p = pcapfile_openread(filename); if (p == NULL) { perror(filename); continue; } for (;;) { unsigned char buf[65536]; int x; unsigned secs; unsigned usecs; unsigned original_length; unsigned bytes_read; x = pcapfile_readframe( p, &secs, &usecs, &original_length, &bytes_read, buf, sizeof(buf) ); if (x <= 0) break; { struct PreprocessedInfo info; unsigned x; x = preprocess_frame( buf, bytes_read, 1, &info); if (x && info.found == FOUND_DNS && info.port_src == 53) grab_dns_response(catalog, buf, info.found_offset, bytes_read); } tracker_report(tracker, bytes_read); } pcapfile_close(p); } return Success; }
/*************************************************************************** * * Asynchronous receive thread * * The transmit and receive threads run independently of each other. There * is no record what was transmitted. Instead, the transmit thread sets a * "SYN-cookie" in transmitted packets, which the receive thread will then * use to match up requests with responses. ***************************************************************************/ static void receive_thread(void *v) { struct ThreadPair *parms = (struct ThreadPair *)v; const struct Masscan *masscan = parms->masscan; struct Output *out; struct DedupTable *dedup; struct PcapFile *pcapfile = NULL; struct TCP_ConnectionTable *tcpcon = 0; LOG(1, "recv: start receive thread #%u\n", parms->nic_index); /* Lock this thread to a CPU. Transmit threads are on even CPUs, * receive threads on odd CPUs */ if (pixie_cpu_get_count() > 1) { unsigned cpu_count = pixie_cpu_get_count(); unsigned cpu = parms->nic_index * 2 + 1; while (cpu >= cpu_count) { cpu -= cpu_count; cpu++; } pixie_cpu_set_affinity(cpu); } /* * If configured, open a --pcap file for saving raw packets. This is * so that we can debug scans, but also so that we can look at the * strange things people send us. Note that we don't record transmitted * packets, just the packets we've received. */ /*if (masscan->pcap_filename[0]) pcapfile = pcapfile_openwrite(masscan->pcap_filename, 1);*/ /* * Open output. This is where results are reported when saving * the --output-format to the --output-filename */ out = output_create(masscan); /* * Create deduplication table. This is so when somebody sends us * multiple responses, we only record the first one. */ dedup = dedup_create(); /* * Create a TCP connection table for interacting with live * connections when doing --banners */ if (masscan->is_banners) { tcpcon = tcpcon_create_table( (size_t)((masscan->max_rate/5) / masscan->nic_count), parms->transmit_queue, parms->packet_buffers, &parms->tmplset->pkts[Proto_TCP], output_report_banner, out, masscan->tcb.timeout ); } if (masscan->is_offline) { while (!control_c_pressed_again) pixie_usleep(10000); parms->done_receiving = 1; return; } /* * Receive packets. This is where we catch any responses and print * them to the terminal. */ LOG(1, "begin receive thread\n"); while (!control_c_pressed_again) { int status; unsigned length; unsigned secs; unsigned usecs; const unsigned char *px; int err; unsigned x; struct PreprocessedInfo parsed; unsigned ip_me; unsigned ip_them; unsigned seqno_them; unsigned seqno_me; /* * RECIEVE * * This is the boring part of actually receiving a packet */ err = rawsock_recv_packet( parms->adapter, &length, &secs, &usecs, &px); if (err != 0) continue; /* * Do any TCP event timeouts based on the current timestamp from * the packet. For example, if the connection has been open for * around 10 seconds, we'll close the connection. (--banners) */ if (tcpcon) { tcpcon_timeouts(tcpcon, secs, usecs); } if (length > 1514) continue; /* * "Preprocess" the response packet. This means to go through and * figure out where the TCP/IP headers are and the locations of * some fields, like IP address and port numbers. */ x = preprocess_frame(px, length, 1, &parsed); if (!x) continue; /* corrupt packet */ ip_me = parsed.ip_dst[0]<<24 | parsed.ip_dst[1]<<16 | parsed.ip_dst[2]<< 8 | parsed.ip_dst[3]<<0; ip_them = parsed.ip_src[0]<<24 | parsed.ip_src[1]<<16 | parsed.ip_src[2]<< 8 | parsed.ip_src[3]<<0; seqno_them = TCP_SEQNO(px, parsed.transport_offset); seqno_me = TCP_ACKNO(px, parsed.transport_offset); /* verify: my IP address */ if (parms->adapter_ip != ip_me) continue; /* * Handle non-TCP protocols */ switch (parsed.found) { case FOUND_ARP: /* OOPS: handle arp instead. Since we may completely bypass the TCP/IP * stack, we may have to handle ARPs ourself, or the router will * lose track of us. */ LOGip(2, ip_them, 0, "-> ARP [%u] \n", px[parsed.found_offset]); arp_response( parms->adapter_ip, parms->adapter_mac, px, length, parms->packet_buffers, parms->transmit_queue); continue; case FOUND_UDP: case FOUND_DNS: if (!is_my_port(masscan, parsed.port_dst)) continue; handle_udp(out, px, length, &parsed); continue; case FOUND_ICMP: handle_icmp(out, px, length, &parsed); continue; case FOUND_TCP: /* fall down to below */ break; default: continue; } /* verify: my port number */ if (parms->adapter_port != parsed.port_dst) continue; /* Save raw packet in --pcap file */ if (pcapfile) { pcapfile_writeframe( pcapfile, px, length, length, secs, usecs); } { char buf[64]; LOGip(5, ip_them, parsed.port_src, "-> TCP ackno=0x%08x flags=0x%02x(%s)\n", seqno_me, TCP_FLAGS(px, parsed.transport_offset), reason_string(TCP_FLAGS(px, parsed.transport_offset), buf, sizeof(buf))); } /* If recording --banners, create a new "TCP Control Block (TCB)" */ if (tcpcon) { struct TCP_Control_Block *tcb; /* does a TCB already exist for this connection? */ tcb = tcpcon_lookup_tcb(tcpcon, ip_me, ip_them, parsed.port_dst, parsed.port_src); if (TCP_IS_SYNACK(px, parsed.transport_offset)) { if (syn_hash(ip_them, parsed.port_src) != seqno_me - 1) { LOG(2, "%u.%u.%u.%u - bad cookie: ackno=0x%08x expected=0x%08x\n", (ip_them>>24)&0xff, (ip_them>>16)&0xff, (ip_them>>8)&0xff, (ip_them>>0)&0xff, seqno_me-1, syn_hash(ip_them, parsed.port_src)); continue; } if (tcb == NULL) { tcb = tcpcon_create_tcb(tcpcon, ip_me, ip_them, parsed.port_dst, parsed.port_src, seqno_me, seqno_them+1); } tcpcon_handle(tcpcon, tcb, TCP_WHAT_SYNACK, 0, 0, secs, usecs, seqno_them+1); } else if (tcb) { /* If this is an ACK, then handle that first */ if (TCP_IS_ACK(px, parsed.transport_offset)) { tcpcon_handle(tcpcon, tcb, TCP_WHAT_ACK, 0, seqno_me, secs, usecs, seqno_them); } /* If this contains payload, handle that */ if (parsed.app_length) { tcpcon_handle(tcpcon, tcb, TCP_WHAT_DATA, px + parsed.app_offset, parsed.app_length, secs, usecs, seqno_them); } /* If this is a FIN, handle that. Note that ACK + * payload + FIN can come together */ if (TCP_IS_FIN(px, parsed.transport_offset) && !TCP_IS_RST(px, parsed.transport_offset)) { tcpcon_handle(tcpcon, tcb, TCP_WHAT_FIN, 0, 0, secs, usecs, seqno_them); } /* If this is a RST, then we'll be closing the connection */ if (TCP_IS_RST(px, parsed.transport_offset)) { tcpcon_handle(tcpcon, tcb, TCP_WHAT_RST, 0, 0, secs, usecs, seqno_them); } } else if (TCP_IS_FIN(px, parsed.transport_offset)) { /* * NO TCB! * This happens when we've sent a FIN, deleted our connection, * but the other side didn't get the packet. */ if (!TCP_IS_RST(px, parsed.transport_offset)) tcpcon_send_FIN( tcpcon, ip_me, ip_them, parsed.port_dst, parsed.port_src, seqno_them, seqno_me); } }
/*************************************************************************** * Print packet info, when using nmap-style --packet-trace option ***************************************************************************/ void packet_trace(FILE *fp, const unsigned char *px, size_t length, unsigned is_sent) { unsigned x; struct PreprocessedInfo parsed; unsigned src_ip; unsigned dst_ip; char from[32]; char to[32]; char sz_type[32]; unsigned type; double timestamp = 1.0 * pixie_gettime() / 1000000.0; unsigned offset; const char *direction; if (is_sent) direction = "SENT"; else direction = "RCVD"; /* parse the packet */ x = preprocess_frame(px, (unsigned)length, 1, &parsed); if (!x) return; offset = parsed.found_offset; src_ip = parsed.ip_src[0] << 24 | parsed.ip_src[1] << 16 | parsed.ip_src[2] << 8 | parsed.ip_src[3]; dst_ip = parsed.ip_dst[0] << 24 | parsed.ip_dst[1] << 16 | parsed.ip_dst[2] << 8 | parsed.ip_dst[3]; /* format the IP addresses into fixed-width fields */ sprintf_s(from, sizeof(from), "%u.%u.%u.%u:%u", (src_ip>>24)&0xFF, (src_ip>>16)&0xFF, (src_ip>>8)&0xFF, (src_ip>>0)&0xFF, parsed.port_src); sprintf_s(to, sizeof(to), "%u.%u.%u.%u:%u", (dst_ip>>24)&0xFF, (dst_ip>>16)&0xFF, (dst_ip>>8)&0xFF, (dst_ip>>0)&0xFF, parsed.port_dst); switch (parsed.found) { case FOUND_ARP: type = px[offset+6]<<8 | px[offset+7]; *strchr(to, ':') = '\0'; *strchr(from, ':') = '\0'; switch (type) { case 1:strcpy_s(sz_type, sizeof(sz_type), "request"); break; case 2:strcpy_s(sz_type, sizeof(sz_type), "response"); break; default: sprintf_s(sz_type, sizeof(sz_type), "unknown(%u)", type); break; } fprintf(fp, "%s (%5.4f) ARP %-21s > %-21s %s\n", direction, timestamp - global_timestamp_start, from, to, sz_type); break; case FOUND_DNS: case FOUND_UDP: fprintf(fp, "%s (%5.4f) UDP %-21s > %-21s \n", direction, timestamp - global_timestamp_start, from, to); break; case FOUND_ICMP: fprintf(fp, "%s (%5.4f) ICMP %-21s > %-21s \n", direction, timestamp - global_timestamp_start, from, to); break; case FOUND_TCP: type = px[offset+13]; switch (type) { case 0x00: strcpy_s(sz_type, sizeof(sz_type), "NULL"); break; case 0x01: strcpy_s(sz_type, sizeof(sz_type), "FIN"); break; case 0x11: strcpy_s(sz_type, sizeof(sz_type), "FIN-ACK"); break; case 0x19: strcpy_s(sz_type, sizeof(sz_type), "FIN-ACK-PSH"); break; case 0x02: strcpy_s(sz_type, sizeof(sz_type), "SYN"); break; case 0x12: strcpy_s(sz_type, sizeof(sz_type), "SYN-ACK"); break; case 0x04: strcpy_s(sz_type, sizeof(sz_type), "RST"); break; case 0x14: strcpy_s(sz_type, sizeof(sz_type), "RST-ACK"); break; case 0x15: strcpy_s(sz_type, sizeof(sz_type), "RST-FIN-ACK"); break; case 0x10: strcpy_s(sz_type, sizeof(sz_type), "ACK"); break; case 0x18: strcpy_s(sz_type, sizeof(sz_type), "ACK-PSH"); break; default: sprintf_s(sz_type, sizeof(sz_type), "%s%s%s%s%s%s%s%s", (type&0x01)?"FIN":"", (type&0x02)?"SYN":"", (type&0x04)?"RST":"", (type&0x08)?"PSH":"", (type&0x10)?"ACK":"", (type&0x20)?"URG":"", (type&0x40)?"ECE":"", (type&0x80)?"CWR":"" ); break; } fprintf(fp, "%s (%5.4f) TCP %-21s > %-21s %s\n", direction, timestamp - global_timestamp_start, from, to, sz_type); break; case FOUND_IPV6: break; default: fprintf(fp, "%s (%5.4f) UNK %-21s > %-21s [%u]\n", direction, timestamp - global_timestamp_start, from, to, parsed.found); break; } }