diff --git a/src/rawnet/rawnetarch_darwin.c b/src/rawnet/rawnetarch_darwin.c index 8855d46..dc362ab 100644 --- a/src/rawnet/rawnetarch_darwin.c +++ b/src/rawnet/rawnetarch_darwin.c @@ -20,6 +20,7 @@ static const uint8_t broadcast_mac[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; static interface_ref interface; static uint8_t interface_mac[6]; +static uint8_t interface_fake_mac[6]; static uint64_t interface_mtu; static uint64_t interface_packet_size; static vmnet_return_t interface_status; @@ -49,6 +50,7 @@ int rawnet_arch_activate(const char *interface_name) { */ memset(interface_mac, 0, sizeof(interface_mac)); + memset(interface_fake_mac, 0, sizeof(interface_fake_mac)); interface_status = 0; interface_mtu = 0; interface_packet_size = 0; @@ -124,7 +126,11 @@ void rawnet_arch_deactivate(void) { } void rawnet_arch_set_mac(const uint8_t mac[6]) { - /* NOP */ + +#ifdef RAWNET_DEBUG_ARCH + log_message( rawnet_arch_log, "New MAC address set: %02X:%02X:%02X:%02X:%02X:%02X.", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] ); +#endif + memcpy(interface_fake_mac, mac, 6); } void rawnet_arch_set_hashfilter(const uint32_t hash_mask[2]) { /* NOP */ @@ -138,12 +144,213 @@ void rawnet_arch_line_ctl(int bEnableTransmitter, int bEnableReceiver) { /* NOP */ } + + + +enum { + eth_dest = 0, // destination address + eth_src = 6, // source address + eth_type = 12, // packet type + eth_data = 14, // packet data +}; + +enum { + ip_ver_ihl = 0, + ip_tos = 1, + ip_len = 2, + ip_id = 4, + ip_frag = 6, + ip_ttl = 8, + ip_proto = 9, + ip_header_cksum = 10, + ip_src = 12, + ip_dest = 16, + ip_data = 20, +}; + +enum { + udp_source = 0, // source port + udp_dest = 2, // destination port + udp_len = 4, // length + udp_cksum = 6, // checksum + udp_data = 8, // total length udp header +}; + +enum { + bootp_op = 0, // operation + bootp_hw = 1, // hardware type + bootp_hlen = 2, // hardware len + bootp_hp = 3, // hops + bootp_transid = 4, // transaction id + bootp_secs = 8, // seconds since start + bootp_flags = 10, // flags + bootp_ipaddr = 12, // ip address knwon by client + bootp_ipclient = 16, // client ip from server + bootp_ipserver = 20, // server ip + bootp_ipgateway = 24, // gateway ip + bootp_client_hrd = 28, // client mac address + bootp_spare = 34, + bootp_host = 44, + bootp_fname = 108, + bootp_data = 236, // total length bootp packet +}; + +enum { + arp_hw = 14, // hw type (eth = 0001) + arp_proto = 16, // protocol (ip = 0800) + arp_hwlen = 18, // hw addr len (eth = 06) + arp_protolen = 19, // proto addr len (ip = 04) + arp_op = 20, // request = 0001, reply = 0002 + arp_shw = 22, // sender hw addr + arp_sp = 28, // sender proto addr + arp_thw = 32, // target hw addr + arp_tp = 38, // target protoaddr + arp_data = 42, // total length of packet +}; + +enum { + dhcp_discover = 1, + dhcp_offer = 2, + dhcp_request = 3, + dhcp_decline = 4, + dhcp_pack = 5, + dhcp_nack = 6, + dhcp_release = 7, + dhcp_inform = 8, +}; + +static uint8_t oo[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static uint8_t ff[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +static int is_arp(const uint8_t *packet, unsigned size) { + return size == arp_data + && packet[12] == 0x08 && packet[13] == 0x06 /* ARP */ + && packet[14] == 0x00 && packet[15] == 0x01 /* ethernet */ + && packet[16] == 0x08 && packet[17] == 0x00 /* ipv4 */ + && packet[18] == 0x06 /* hardware size */ + && packet[19] == 0x04 /* protocol size */ + ; +} + +static int is_broadcast(const uint8_t *packet, unsigned size) { + return !memcmp(packet + 0, ff, 6); +} + +static int is_unicast(const uint8_t *packet, unsigned size) { + return (*packet & 0x01) == 0; +} + +static int is_multicast(const uint8_t *packet, unsigned size) { + return (*packet & 0x01) == 0x01 && !is_broadcast(packet, size); +} + +static int is_dhcp_out(const uint8_t *packet, unsigned size) { + static uint8_t cookie[] = { 0x63, 0x82, 0x53, 0x63 }; + return size >= 282 + //&& !memcmp(&packet[0], ff, 6) /* broadcast */ + && packet[12] == 0x08 && packet[13] == 0x00 + && packet[14] == 0x45 /* version 4 */ + && packet[23] == 0x11 /* UDP */ + //&& !memcmp(&packet[26], oo, 4) /* source ip */ + //&& !memcmp(&packet[30], ff, 4) /* dest ip */ + && packet[34] == 0x00 && packet[35] == 0x44 /* source port */ + && packet[36] == 0x00 && packet[37] == 0x43 /* dest port */ + //&& packet[44] == 0x01 /* dhcp boot req */ + && packet[43] == 0x01 /* ethernet */ + && packet[44] == 0x06 /* 6 byte mac */ + && !memcmp(&packet[278], cookie, 4) + ; +} + + +static int is_dhcp_in(const uint8_t *packet, unsigned size) { + static uint8_t cookie[] = { 0x63, 0x82, 0x53, 0x63 }; + return size >= 282 + //&& !memcmp(&packet[0], ff, 6) /* broadcast */ + && packet[12] == 0x08 && packet[13] == 0x00 + && packet[14] == 0x45 /* version 4 */ + && packet[23] == 0x11 /* UDP */ + //&& !memcmp(&packet[26], oo, 4) /* source ip */ + //&& !memcmp(&packet[30], ff, 4) /* dest ip */ + && packet[34] == 0x00 && packet[35] == 0x43 /* source port */ + && packet[36] == 0x00 && packet[37] == 0x44 /* dest port */ + //&& packet[44] == 0x01 /* dhcp boot req */ + && packet[43] == 0x01 /* ethernet */ + && packet[44] == 0x06 /* 6 byte mac */ + && !memcmp(&packet[278], cookie, 4) + ; +} + +static unsigned ip_checksum(const uint8_t *packet) { + unsigned x = 0; + unsigned i; + for (i = 0; i < ip_data; i += 2) { + if (i == ip_header_cksum) continue; + x += packet[eth_data + i + 0 ] << 8; + x += packet[eth_data + i + 1]; + } + + /* add the carry */ + x += x >> 16; + x &= 0xffff; + return ~x & 0xffff; +} + +static void fix_incoming_packet(uint8_t *packet, unsigned size, const uint8_t real_mac[6], const uint8_t fake_mac[6]) { + + if (memcmp(packet + 0, real_mac, 6) == 0) + memcpy(packet + 0, fake_mac, 6); + + /* dhcp request - fix the hardware address */ + if (is_unicast(packet, size) && is_dhcp_in(packet, size)) { + if (!memcmp(packet + 70, real_mac, 6)) + memcpy(packet + 70, fake_mac, 6); + return; + } + +} + +static void fix_outgoing_packet(uint8_t *packet, unsigned size, const uint8_t real_mac[6], const uint8_t fake_mac[6]) { + + + + if (memcmp(packet + 6, fake_mac, 6) == 0) + memcpy(packet + 6, real_mac, 6); + + if (is_arp(packet, size)) { + /* sender mac address */ + if (!memcmp(packet + 22, fake_mac, 6)) + memcpy(packet + 22, real_mac, 6); + return; + } + + /* dhcp request - fix the hardware address */ + if (is_broadcast(packet, size) && is_dhcp_out(packet, size)) { + /* set source ip to 0 - LL bug? */ + /* fixed in link layer as of 2018-12-17 */ +#if 0 + unsigned ck; + memset(packet + 26, 0, 4); + ck = ip_checksum(packet); + packet[eth_data + ip_header_cksum + 0] = ck >> 8; + packet[eth_data + ip_header_cksum + 1] = ck; +#endif + + if (!memcmp(packet + 70, fake_mac, 6)) + memcpy(packet + 70, real_mac, 6); + return; + } + +} + + void rawnet_arch_transmit(int force, int onecoll, int inhibit_crc, int tx_pad_dis, int txlength, uint8_t *txframe) { int count = 1; vmnet_return_t st; struct vmpktdesc v; struct iovec iov; + uint8_t *buffer; if (txlength == 0) return; if (txlength > interface_packet_size) { @@ -151,8 +358,17 @@ void rawnet_arch_transmit(int force, int onecoll, int inhibit_crc, int tx_pad_di return; } + if (txlength < 12) { + log_message(rawnet_arch_log, "packet is too small: %d", txlength); + return; + } - iov.iov_base = txframe; + /* copy the buffer and fix the source mac address. */ + buffer = (uint8_t *)calloc(txlength, 1); + memcpy(buffer, txframe, txlength); + fix_outgoing_packet(buffer, txlength, interface_mac, interface_fake_mac); + + iov.iov_base = buffer; iov.iov_len = txlength; v.vm_pkt_size = txlength; @@ -161,11 +377,12 @@ void rawnet_arch_transmit(int force, int onecoll, int inhibit_crc, int tx_pad_di v.vm_flags = 0; - fprintf(stderr, "\rawnet_arch_transmit: %u\n", (unsigned)iov.iov_len); - rawnet_hexdump(iov.iov_base, iov.iov_len); + fprintf(stderr, "\nrawnet_arch_transmit: %u\n", (unsigned)iov.iov_len); + rawnet_hexdump(buffer, v.vm_pkt_size); st = vmnet_write(interface, &v, &count); + free(buffer); if (st != VMNET_SUCCESS) { log_message(rawnet_arch_log, "vmnet_write failed!"); } @@ -174,7 +391,7 @@ void rawnet_arch_transmit(int force, int onecoll, int inhibit_crc, int tx_pad_di int rawnet_arch_receive(uint8_t *pbuffer, int *plen, int *phashed, int *phash_index, int *prx_ok, int *pcorrect_mac, int *pbroadcast, int *pcrc_error) { - char *buffer; + uint8_t *buffer; //unsigned hashreg; int count = 1; @@ -184,7 +401,7 @@ int rawnet_arch_receive(uint8_t *pbuffer, int *plen, int *phashed, int *phash_in struct iovec iov; - buffer = calloc(interface_packet_size, 1); + buffer = (uint8_t *)calloc(interface_packet_size, 1); iov.iov_base = buffer; iov.iov_len = interface_packet_size; @@ -206,9 +423,13 @@ int rawnet_arch_receive(uint8_t *pbuffer, int *plen, int *phashed, int *phash_in return 0; } + fix_incoming_packet(buffer, v.vm_pkt_size, interface_mac, interface_fake_mac); + // iov.iov_len is not updated with the read count, apparently. - fprintf(stderr, "\nrawnet_arch_receive: %u\n", (unsigned)v.vm_pkt_size); - rawnet_hexdump(iov.iov_base, v.vm_pkt_size); + if (!is_multicast(buffer, v.vm_pkt_size)) { /* multicast crap */ + fprintf(stderr, "\nrawnet_arch_receive: %u\n", (unsigned)v.vm_pkt_size); + rawnet_hexdump(buffer, v.vm_pkt_size); + } xfer = v.vm_pkt_size; if (xfer > *plen) xfer = *plen; @@ -225,9 +446,11 @@ int rawnet_arch_receive(uint8_t *pbuffer, int *plen, int *phashed, int *phash_in *pcrc_error = 0; *prx_ok = 1; + #if 0 *pcorrect_mac = memcmp(buffer, interface_mac, 6) == 0; *pbroadcast = memcmp(buffer, broadcast_mac, 6) == 0; - + #endif + /* vmnet won't send promiscuous packets */ #if 0 hashreg = (~crc32_buf(buffer, 6) >> 26) & 0x3f;