darwin rawnet - since the MAC address can't change, switch it with Uthernet's mac address. Unfortunately, dhcp requests include a mac address, so it also has to be swapped in the DHCP message.

This commit is contained in:
Kelvin Sherlock 2018-12-18 19:23:57 -05:00
parent 9370ed8604
commit b98635aaf1
1 changed files with 232 additions and 9 deletions

View File

@ -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;