diff --git a/src/config.c b/src/config.c index ff6b9b7..f246b11 100644 --- a/src/config.c +++ b/src/config.c @@ -27,11 +27,12 @@ main_config_t get_main_config(void) main_config_t config; - config.udp_port = DEFAULT_PORT; - config.w95_bug = true; - config.fw_except = false; - config.use_pcap = false; - config.log_level = LOG_INFO; + config.udp_port = DEFAULT_PORT; + config.w95_bug = true; + config.fw_except = false; + config.use_pcap = false; + config.frame_type = FRAME_TYPE_ETH_II; + config.log_level = LOG_INFO; HKEY reg = reg_open_main(false); @@ -49,11 +50,24 @@ main_config_t get_main_config(void) /* Overlay with any 0.4.x config values. */ - config.udp_port = reg_get_dword(reg, "port", config.udp_port); - config.w95_bug = reg_get_dword(reg, "w95_bug", config.w95_bug); - config.fw_except = reg_get_dword(reg, "fw_except", config.fw_except); - config.use_pcap = reg_get_dword(reg, "use_pcap", config.use_pcap); - config.log_level = reg_get_dword(reg, "log_level", config.log_level); + config.udp_port = reg_get_dword(reg, "port", config.udp_port); + config.w95_bug = reg_get_dword(reg, "w95_bug", config.w95_bug); + config.fw_except = reg_get_dword(reg, "fw_except", config.fw_except); + config.use_pcap = reg_get_dword(reg, "use_pcap", config.use_pcap); + config.frame_type = reg_get_dword(reg, "frame_type", config.frame_type); + config.log_level = reg_get_dword(reg, "log_level", config.log_level); + + /* Check for valid frame_type */ + + if( config.frame_type != FRAME_TYPE_ETH_II + && config.frame_type != FRAME_TYPE_NOVELL) + { + + log_printf(LOG_WARNING, "Ignoring unknown frame_type %u", + (unsigned int)(config.frame_type)); + + config.frame_type = FRAME_TYPE_ETH_II; + } reg_close(reg); @@ -64,11 +78,12 @@ bool set_main_config(const main_config_t *config) { HKEY reg = reg_open_main(true); - bool ok = reg_set_dword(reg, "port", config->udp_port) - && reg_set_dword(reg, "w95_bug", config->w95_bug) - && reg_set_dword(reg, "fw_except", config->fw_except) - && reg_set_dword(reg, "use_pcap", config->use_pcap) - && reg_set_dword(reg, "log_level", config->log_level); + bool ok = reg_set_dword(reg, "port", config->udp_port) + && reg_set_dword(reg, "w95_bug", config->w95_bug) + && reg_set_dword(reg, "fw_except", config->fw_except) + && reg_set_dword(reg, "use_pcap", config->use_pcap) + && reg_set_dword(reg, "frame_type", config->frame_type) + && reg_set_dword(reg, "log_level", config->log_level); reg_close(reg); diff --git a/src/config.h b/src/config.h index 28e3eb1..cd6872b 100644 --- a/src/config.h +++ b/src/config.h @@ -26,12 +26,19 @@ extern "C" { #endif +enum main_config_frame_type +{ + FRAME_TYPE_ETH_II = 1, + FRAME_TYPE_NOVELL = 2 +}; + typedef struct main_config { uint16_t udp_port; bool w95_bug; bool fw_except; bool use_pcap; + enum main_config_frame_type frame_type; enum ipx_log_level log_level; } main_config_t; diff --git a/src/ipxwrapper.h b/src/ipxwrapper.h index a63c2a7..33207fc 100644 --- a/src/ipxwrapper.h +++ b/src/ipxwrapper.h @@ -116,7 +116,11 @@ struct ethernet_frame unsigned char dest_mac[6]; unsigned char src_mac[6]; - uint16_t ethertype; + union { + /* Depends on frame type. */ + uint16_t ethertype; + uint16_t length; + }; real_ipx_packet_t packet; } __attribute__((__packed__)); diff --git a/src/router.c b/src/router.c index cbf4baa..f6447f7 100644 --- a/src/router.c +++ b/src/router.c @@ -505,10 +505,43 @@ static void _handle_pcap_frame(u_char *user, const struct pcap_pkthdr *pkt_heade ethernet_frame_t *frame = (ethernet_frame_t*)(pkt_data); - if(ntohs(frame->ethertype) != 0x8137) + uint16_t ipx_packet_len = ntohs(frame->packet.length); + + if(main_config.frame_type == FRAME_TYPE_ETH_II) { - /* The ethertype field isn't IPX. */ - return; + /* Configured for standard Ethernet. */ + + if(ntohs(frame->ethertype) != 0x8137) + { + /* The ethertype field isn't IPX. */ + return; + } + } + else if(main_config.frame_type == FRAME_TYPE_NOVELL) + { + /* Configured for Novell "raw" Ethernet. */ + + uint16_t eth_payload_len = ntohs(frame->length); + + if(eth_payload_len > 1500) + { + /* Too big, must be an Ethernet II frame (or garbage). */ + return; + } + else if(eth_payload_len < sizeof(frame->packet)) + { + /* Too small to hold an IPX header. */ + return; + } + else if(eth_payload_len < ipx_packet_len) + { + /* Too small to hold the IPX payload within. */ + return; + } + } + else{ + /* Unknown frame type configured. */ + abort(); } if(frame->packet.checksum != 0xFFFF) @@ -517,7 +550,7 @@ static void _handle_pcap_frame(u_char *user, const struct pcap_pkthdr *pkt_heade return; } - if(ntohs(frame->packet.length) > (pkt_header->caplen - (sizeof(*frame) - sizeof(frame->packet)))) + if(ipx_packet_len > (pkt_header->caplen - (sizeof(*frame) - sizeof(frame->packet)))) { /* The "length" field in the IPX header is too big. */ return; diff --git a/src/winsock.c b/src/winsock.c index 6b3d9b2..893de37 100644 --- a/src/winsock.c +++ b/src/winsock.c @@ -1206,13 +1206,41 @@ static DWORD ipx_send_packet( return ERROR_OUTOFMEMORY; } - log_printf(LOG_DEBUG, "...packet size = %d, frame size = %d", + log_printf(LOG_DEBUG, "...packet size = %u, frame size = %u", (unsigned int)(packet_size), (unsigned int)(frame_size)); addr48_out(frame->dest_mac, dest_node); addr48_out(frame->src_mac, iface->mac_addr); - frame->ethertype = htons(0x8137); + if(main_config.frame_type == FRAME_TYPE_ETH_II) + { + /* Configured for standard Ethernet. */ + frame->ethertype = htons(0x8137); + } + else if(main_config.frame_type == FRAME_TYPE_NOVELL) + { + /* Configured for Novell "raw" Ethernet. */ + + if(packet_size > 1500) + { + /* Can't fit a payload this big into a + * Novell Ethernet frame. + */ + + log_printf(LOG_ERROR, + "Tried sending a %u byte packet in a Novell (\"raw\") Ethernet frame", + (unsigned int)(packet_size)); + + free(frame); + return WSAEMSGSIZE; + } + + frame->length = htons(packet_size); + } + else{ + /* Unknown frame type configured. */ + abort(); + } frame->packet.checksum = 0xFFFF; frame->packet.length = htons(packet_size);