/* * router.cpp - ip router * * Basilisk II (C) 1997-2001 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * This could be implemented by writing three (9x,nt,2k) * NDIS filter drivers. No thanks. * But this is not easy either. */ #include "sysdeps.h" #define WIN32_LEAN_AND_MEAN #include #include #include "cpu_emulation.h" #include "prefs.h" #include "ether_windows.h" #include "ether.h" #include "router.h" #include "router_types.h" #include "dynsockets.h" #include "ipsocket.h" #include "iphelp.h" #include "arp.h" #include "icmp.h" #include "udp.h" #include "tcp.h" #include "ftp.h" #include "mib/interfaces.h" #include "dump.h" #if DEBUG #pragma optimize("",off) #endif #include "debug.h" uint16 next_ip_ident_number = 1; uint32 macos_ip_address = 0; const uint8 router_mac_addr[6] = { '4', '2', '6', '7', '7', '9' }; uint32 router_ip_address = 0; bool raw_sockets_available = false; // Protected data. CRITICAL_SECTION router_section; bool is_router_shutting_down = false; static HANDLE r_handle = 0; static unsigned int rh_tid = 0; static void write_ip4( ip_t *ip, int len ) { if(len < sizeof(ip_t)) { D(bug("Too small ip packet(%d), dropped\r\n", len)); } else { uint8 proto = ip->proto; // This is a router, decrement the hop count if( --ip->ttl == 0 ) { // Most likely this is some Mac traceroute app D(bug("ip packet ttl expired, proto=%d.\r\n", proto)); error_winsock_2_icmp( WSAETTLEXCEEDED, ip, len ); } else { switch( proto ) { case ip_proto_icmp: write_icmp( (icmp_t *)ip, len ); break; case ip_proto_tcp: write_tcp( (tcp_t *)ip, len ); break; case ip_proto_udp: write_udp( (udp_t *)ip, len ); break; default: D(bug("write_ip4() len=%d, proto=%d\r\n", len, proto)); break; } } } } bool router_write_packet(uint8 *packet, int len) { bool result = false; if( len >= 14 ) { switch( ntohs( ((mac_t *)packet)->type ) ) { case mac_type_ip4: write_ip4( (ip_t *)packet, len ); result = true; break; case mac_type_ip6: D(bug("write_ip6() len=%d; unsupported.\r\n", len)); result = true; break; case mac_type_arp: result = write_arp( (arp_t *)packet, len ); break; } } return result; } bool router_read_packet(uint8 *packet, int len) { bool result = false; if( len >= 14 ) { switch( ntohs( ((mac_t *)packet)->type ) ) { case mac_type_ip4: case mac_type_ip6: case mac_type_arp: result = true; break; } } return result; } /* This has nothing to do with TCP TIME_WAITs or CLOSE_WAITs, the thread is needed to close down expired udp sockets. Arguably an ugly hack, but needed since there is no way to listen to all ports w/o writing another ndis filter driver */ static WINAPI unsigned int router_expire_thread(void *arg) { while(!is_router_shutting_down) { close_old_sockets(); Sleep(1000); } return 0; } bool router_init(void) { InitializeCriticalSection( &router_section ); if(dynsockets_init()) { char me[128]; if( _gethostname(me, sizeof(me)) == SOCKET_ERROR ) { D(bug("gethostname() failed, error = %d\r\n", _WSAGetLastError())); } else { struct hostent *hent = _gethostbyname(me); if( hent == NULL ) { D(bug("gethostbyname() failed, error = %d\r\n", _WSAGetLastError())); } else { struct in_addr *ina = (struct in_addr *) *hent->h_addr_list; router_ip_address = ntohl(ina->s_addr); D(bug("router protocol address seems to be %s (used only in icmp error messages)\r\n", _inet_ntoa(*ina))); } } is_router_shutting_down = false; r_handle = (HANDLE)_beginthreadex( 0, 0, router_expire_thread, 0, 0, &rh_tid ); init_interfaces(); init_tcp(); init_udp(); init_ftp(); return true; } return false; } void router_final(void) { final_interfaces(); stop_icmp_listen(); close_all_sockets(); if(r_handle) { is_router_shutting_down = true; WaitForSingleObject( r_handle, INFINITE ); final_tcp(); final_udp(); dynsockets_final(); } DeleteCriticalSection( &router_section ); }