void sr_handlepacket(struct sr_instance* sr, uint8_t * packet/* lent */, unsigned int len, char* interface/* lent */) { /* REQUIRES */ assert(sr); assert(packet); assert(interface); printf("*** -> Received packet of length %d \n",len); uint8_t *pkt = malloc(len); memcpy(pkt, packet, len); sr_ethernet_hdr_t *hdr = get_ethernet_hdr(pkt); enum sr_ethertype type = ntohs(hdr->ether_type); if (type == ethertype_arp) { char *inf_cpy = malloc(sr_IFACE_NAMELEN); memcpy(inf_cpy, interface, sr_IFACE_NAMELEN); handle_arp(sr, pkt, inf_cpy, len); } else if (type == ethertype_ip) { handle_ip(sr, pkt, len); } else { fprintf(stderr, "invalid packet type id in ethernet header\n"); } }/* end sr_ForwardPacket */
void handle_ether(const struct timeval& t, WifipcapCallbacks *cbs, const u_char *ptr, int len) { ether_hdr_t hdr; hdr.da = ether2MAC(ptr); hdr.sa = ether2MAC(ptr+6); hdr.type = EXTRACT_16BITS(ptr + 12); ptr += 14; len -= 14; cbs->HandleEthernet(t, &hdr, ptr, len); switch (hdr.type) { case ETHERTYPE_IP: handle_ip(t, cbs, ptr, len); return; case ETHERTYPE_IPV6: handle_ip6(t, cbs, ptr, len); return; case ETHERTYPE_ARP: handle_arp(t, cbs, ptr, len); return; default: cbs->HandleL2Unknown(t, hdr.type, ptr, len); return; } }
/** * Ethernet: Receives an ethernet-packet and handles it according to * Receive-handle diagram. * * @return ZERO - packet was handled or no packets received; * NON ZERO - error condition occurs. */ int32_t receive_ether(void) { int32_t bytes_received; struct ethhdr * ethh; memset(ether_packet, 0, ETH_MTU_SIZE); bytes_received = recv(0, ether_packet, ETH_MTU_SIZE, 0); if (!bytes_received) // No messages return 0; if (bytes_received < sizeof(struct ethhdr)) return -1; // packet is too small ethh = (struct ethhdr *) ether_packet; if(memcmp(ethh->dest_mac, broadcast_mac, 6) != 0 && memcmp(ethh->dest_mac, multicast_mac, 3) != 0 && memcmp(ethh->dest_mac, own_mac, 6 ) != 0 && !is_multicast_mac(ethh->dest_mac)) return -1; // packet is too small switch (htons(ethh -> type)) { case ETHERTYPE_IP: return handle_ipv4((uint8_t*) (ethh + 1), bytes_received - sizeof(struct ethhdr)); /* case ETHERTYPE_IPv6: return handle_ipv6(ether_packet + sizeof(struct ethhdr), bytes_received - sizeof(struct ethhdr)); */ case ETHERTYPE_ARP: return handle_arp((uint8_t*) (ethh + 1), bytes_received - sizeof(struct ethhdr)); default: break; } return -1; // unknown protocol }
static void read_packet(unsigned char* buf, uint16_t len) { if (len < sizeof(struct ether_header)) { lput_str("Ethernet header was too short"); return; } struct ether_header* eth = (struct ether_header*)buf; if (memcmp(eth->dest, MAC_ADDRESS, ETHER_ADDR_LEN) != 0 && memcmp(eth->dest, BROADCAST_ADDRESS, ETHER_ADDR_LEN) != 0) { lput_str("Ignoring packet not meant for me"); return; } uint16_t payload_len = len - sizeof(struct ether_header); unsigned char* payload = (unsigned char*)(eth + 1); ntohs(ð->type); switch (eth->type) { case ETHERTYPE_IP: if (payload_len < sizeof(struct ip_header)) { lput_str("IP header was too short"); return; } unsigned char* ip_payload = payload + sizeof(struct ip_header); uint16_t ip_payload_len = payload_len - sizeof(struct ip_header); handle_ip((struct ip_header*)payload, ip_payload, ip_payload_len); break; case ETHERTYPE_ARP: if (payload_len < sizeof(struct arp_header)) { lput_str("ARP header was too short"); return; } handle_arp((struct arp_header*)payload); break; default: lput_str("Unknown ETHERTYPE:"); lput16_hex(eth->type); lput_str("\r\n"); break; } }
/*************************************************************************** * * 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->http_user_agent_length) tcpcon_set_parameter( tcpcon, "http-user-agent", masscan->http_user_agent_length, masscan->http_user_agent); } /* * In "offline" mode, we don't have any receive threads, so simply * wait until transmitter thread is done then go to the end */ if (masscan->is_offline) { while (!control_c_pressed_again) pixie_usleep(10000); parms->done_receiving = 1; goto end; } /* * 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 port_me; unsigned ip_them; unsigned port_them; unsigned seqno_me; unsigned seqno_them; unsigned cookie; /* * 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; port_me = parsed.port_dst; port_them = parsed.port_src; seqno_them = TCP_SEQNO(px, parsed.transport_offset); seqno_me = TCP_ACKNO(px, parsed.transport_offset); cookie = syn_cookie(ip_them, port_them, ip_me, port_me) & 0xFFFFFFFF; /* verify: my IP address */ if (!is_my_ip(&parms->src, ip_me)) continue; /* * Handle non-TCP protocols */ switch (parsed.found) { case FOUND_ARP: LOGip(2, ip_them, 0, "-> ARP [%u] \n", px[parsed.found_offset]); switch (px[parsed.found_offset + 6]<<8 | px[parsed.found_offset+7]) { case 1: /* request */ /* This function will transmit a "reply" to somebody's ARP request * for our IP address (as part of our user-mode TCP/IP). * Since we completely bypass the TCP/IP stack, we have to handle ARPs * ourself, or the router will lose track of us.*/ arp_response( ip_me, parms->adapter_mac, px, length, parms->packet_buffers, parms->transmit_queue); break; case 2: /* response */ /* This is for "arp scan" mode, where we are ARPing targets rather * than port scanning them */ /* If we aren't doing an ARP scan, then ignore ARP responses */ if (!masscan->is_arp) break; /* If this response isn't in our range, then ignore it */ if (!rangelist_is_contains(&masscan->targets, ip_them)) break; /* Ignore duplicates */ if (dedup_is_duplicate(dedup, ip_them, 0)) continue; /* ...everything good, so now report this response */ handle_arp(out, px, length, &parsed); break; } continue; case FOUND_UDP: case FOUND_DNS: if (!is_nic_port(masscan, port_me)) continue; if (parms->masscan->nmap.packet_trace) packet_trace(stdout, px, length, 0); 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 (!is_my_port(&parms->src, port_me)) continue; if (parms->masscan->nmap.packet_trace) packet_trace(stdout, px, length, 0); /* Save raw packet in --pcap file */ if (pcapfile) { pcapfile_writeframe( pcapfile, px, length, length, secs, usecs); } { char buf[64]; LOGip(5, ip_them, port_them, "-> 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, port_me, port_them); if (TCP_IS_SYNACK(px, parsed.transport_offset)) { if (cookie != 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, cookie); continue; } if (tcb == NULL) { tcb = tcpcon_create_tcb(tcpcon, ip_me, ip_them, port_me, port_them, 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, port_me, port_them, seqno_them, seqno_me); } }