diff options
Diffstat (limited to 'slirp/slirp.c')
-rw-r--r-- | slirp/slirp.c | 749 |
1 files changed, 0 insertions, 749 deletions
diff --git a/slirp/slirp.c b/slirp/slirp.c deleted file mode 100644 index d6eaac4..0000000 --- a/slirp/slirp.c +++ /dev/null @@ -1,749 +0,0 @@ -#include "slirp.h" -#include "proxy_common.h" -#include "android_utils.h" /* for dprint */ -#include "android.h" - -#define D(...) VERBOSE_PRINT(slirp,__VA_ARGS__) -#define DN(...) do { if (VERBOSE_CHECK(slirp)) dprintn(__VA_ARGS__); } while (0) - -/* host address */ -struct in_addr our_addr; -/* host dns address */ -struct in_addr dns_addr[DNS_ADDR_MAX]; -int dns_addr_count; - -/* host loopback address */ -struct in_addr loopback_addr; - -/* address for slirp virtual addresses */ -struct in_addr special_addr; -/* virtual address alias for host */ -struct in_addr alias_addr; - -const uint8_t special_ethaddr[6] = { - 0x52, 0x54, 0x00, 0x12, 0x35, 0x00 -}; - -uint8_t client_ethaddr[6] = { - 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 -}; - -int do_slowtimo; -int link_up; -struct timeval tt; -FILE *lfd; - -/* XXX: suppress those select globals */ -fd_set *global_readfds, *global_writefds, *global_xfds; - -char slirp_hostname[33]; - -int slirp_add_dns_server(struct in_addr new_dns_addr) -{ - if (dns_addr_count >= DNS_ADDR_MAX) - return -1; - - dns_addr[dns_addr_count++] = new_dns_addr; - return 0; -} - - -#ifdef _WIN32 - -int slirp_get_system_dns_servers() -{ - FIXED_INFO *FixedInfo=NULL; - ULONG BufLen; - DWORD ret; - IP_ADDR_STRING *pIPAddr; - struct in_addr tmp_addr; - - if (dns_addr_count > 0) - return dns_addr_count; - - FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO)); - BufLen = sizeof(FIXED_INFO); - - if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) { - if (FixedInfo) { - GlobalFree(FixedInfo); - FixedInfo = NULL; - } - FixedInfo = GlobalAlloc(GPTR, BufLen); - } - - if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) { - printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret ); - if (FixedInfo) { - GlobalFree(FixedInfo); - FixedInfo = NULL; - } - return -1; - } - - D( "DNS Servers:"); - pIPAddr = &(FixedInfo->DnsServerList); - while (pIPAddr && dns_addr_count < DNS_ADDR_MAX) { - D( " %s", pIPAddr->IpAddress.String ); - inet_aton(pIPAddr->IpAddress.String, &tmp_addr); - if (tmp_addr.s_addr == loopback_addr.s_addr) - tmp_addr = our_addr; - if (dns_addr_count < DNS_ADDR_MAX) - dns_addr[dns_addr_count++] = tmp_addr; - pIPAddr = pIPAddr->Next; - } - - if (FixedInfo) { - GlobalFree(FixedInfo); - FixedInfo = NULL; - } - if (dns_addr_count <= 0) - return -1; - - return dns_addr_count; -} - -#else - -int slirp_get_system_dns_servers(void) -{ - char buff[512]; - char buff2[256]; - FILE *f; - struct in_addr tmp_addr; - - if (dns_addr_count > 0) - return dns_addr_count; - -#ifdef CONFIG_DARWIN - /* on Darwin /etc/resolv.conf is a symlink to /private/var/run/resolv.conf - * in some siutations, the symlink can be destroyed and the system will not - * re-create it. Darwin-aware applications will continue to run, but "legacy" - * Unix ones will not. - */ - f = fopen("/private/var/run/resolv.conf", "r"); - if (!f) - f = fopen("/etc/resolv.conf", "r"); /* desperate attempt to sanity */ -#else - f = fopen("/etc/resolv.conf", "r"); -#endif - if (!f) - return -1; - - DN("emulator: IP address of your DNS(s): "); - while (fgets(buff, 512, f) != NULL) { - if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) { - if (!inet_aton(buff2, &tmp_addr)) - continue; - if (tmp_addr.s_addr == loopback_addr.s_addr) - tmp_addr = our_addr; - if (dns_addr_count < DNS_ADDR_MAX) { - dns_addr[dns_addr_count++] = tmp_addr; - if (dns_addr_count > 1) - DN(", "); - DN("%s", inet_ntoa(tmp_addr)); - } else { - DN("(more)"); - break; - } - } - } - DN("\n"); - fclose(f); - - if (!dns_addr_count) - return -1; - - return dns_addr_count; -} - -#endif - -extern void slirp_init_shapers(); - -void slirp_init(void) -{ -#if DEBUG - int slirp_logmask = 0; - char slirp_logfile[512]; - - { - const char* env = getenv( "ANDROID_SLIRP_LOGMASK" ); - if (env != NULL) - slirp_logmask = atoi(env); - else if (VERBOSE_CHECK(slirp)) - slirp_logmask = DEBUG_DEFAULT; - } - - { - char* p = slirp_logfile; - char* end = p + sizeof(slirp_logfile); - - p = bufprint_temp_file( p, end, "slirp.log" ); - if (p >= end) { - dprint( "cannot create slirp log file in temporary directory" ); - slirp_logmask = 0; - } - } - if (slirp_logmask) { - dprint( "sending slirp logs with mask %x to %s", slirp_logmask, slirp_logfile ); - debug_init( slirp_logfile, slirp_logmask ); - } -#endif - - link_up = 1; - - if_init(); - ip_init(); - - /* Initialise mbufs *after* setting the MTU */ - mbuf_init(); - - /* set default addresses */ - inet_aton("127.0.0.1", &loopback_addr); - - if (dns_addr_count == 0) { - if (slirp_get_system_dns_servers() < 0) { - dns_addr[0] = loopback_addr; - dns_addr_count = 1; - fprintf (stderr, "Warning: No DNS servers found\n"); - } - } - - inet_aton(CTL_SPECIAL, &special_addr); - alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS); - getouraddr(); - - slirp_init_shapers(); -} - -#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) -#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) -#define UPD_NFDS(x) if (nfds < (x)) nfds = (x) - -/* - * curtime kept to an accuracy of 1ms - */ -#ifdef _WIN32 -static void updtime(void) -{ - struct _timeb tb; - - _ftime(&tb); - curtime = (u_int)tb.time * (u_int)1000; - curtime += (u_int)tb.millitm; -} -#else -static void updtime(void) -{ - gettimeofday(&tt, 0); - - curtime = (u_int)tt.tv_sec * (u_int)1000; - curtime += (u_int)tt.tv_usec / (u_int)1000; - - if ((tt.tv_usec % 1000) >= 500) - curtime++; -} -#endif - -void slirp_select_fill(int *pnfds, - fd_set *readfds, fd_set *writefds, fd_set *xfds) -{ - struct socket *so, *so_next; - struct timeval timeout; - int nfds; - int tmp_time; - - /* fail safe */ - global_readfds = NULL; - global_writefds = NULL; - global_xfds = NULL; - - nfds = *pnfds; - /* - * First, TCP sockets - */ - do_slowtimo = 0; - if (link_up) { - /* - * *_slowtimo needs calling if there are IP fragments - * in the fragment queue, or there are TCP connections active - */ - do_slowtimo = ((tcb.so_next != &tcb) || - ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next)); - - for (so = tcb.so_next; so != &tcb; so = so_next) { - so_next = so->so_next; - - /* - * See if we need a tcp_fasttimo - */ - if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) - time_fasttimo = curtime; /* Flag when we want a fasttimo */ - - /* - * NOFDREF can include still connecting to local-host, - * newly socreated() sockets etc. Don't want to select these. - */ - if (so->so_state & SS_NOFDREF || so->s == -1) - continue; - - /* - * don't register proxified socked connections here - */ - if ((so->so_state & SS_PROXIFIED) != 0) - continue; - - /* - * Set for reading sockets which are accepting - */ - if (so->so_state & SS_FACCEPTCONN) { - FD_SET(so->s, readfds); - UPD_NFDS(so->s); - continue; - } - - /* - * Set for writing sockets which are connecting - */ - if (so->so_state & SS_ISFCONNECTING) { - FD_SET(so->s, writefds); - UPD_NFDS(so->s); - continue; - } - - /* - * Set for writing if we are connected, can send more, and - * we have something to send - */ - if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) { - FD_SET(so->s, writefds); - UPD_NFDS(so->s); - } - - /* - * Set for reading (and urgent data) if we are connected, can - * receive more, and we have room for it XXX /2 ? - */ - if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) { - FD_SET(so->s, readfds); - FD_SET(so->s, xfds); - UPD_NFDS(so->s); - } - } - - /* - * UDP sockets - */ - for (so = udb.so_next; so != &udb; so = so_next) { - so_next = so->so_next; - - if ((so->so_state & SS_PROXIFIED) != 0) - continue; - - /* - * See if it's timed out - */ - if (so->so_expire) { - if (so->so_expire <= curtime) { - udp_detach(so); - continue; - } else - do_slowtimo = 1; /* Let socket expire */ - } - - /* - * When UDP packets are received from over the - * link, they're sendto()'d straight away, so - * no need for setting for writing - * Limit the number of packets queued by this session - * to 4. Note that even though we try and limit this - * to 4 packets, the session could have more queued - * if the packets needed to be fragmented - * (XXX <= 4 ?) - */ - if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) { - FD_SET(so->s, readfds); - UPD_NFDS(so->s); - } - } - } - - /* - * Setup timeout to use minimum CPU usage, especially when idle - */ - - /* - * First, see the timeout needed by *timo - */ - timeout.tv_sec = 0; - timeout.tv_usec = -1; - /* - * If a slowtimo is needed, set timeout to 500ms from the last - * slow timeout. If a fast timeout is needed, set timeout within - * 200ms of when it was requested. - */ - if (do_slowtimo) { - /* XXX + 10000 because some select()'s aren't that accurate */ - timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000; - if (timeout.tv_usec < 0) - timeout.tv_usec = 0; - else if (timeout.tv_usec > 510000) - timeout.tv_usec = 510000; - - /* Can only fasttimo if we also slowtimo */ - if (time_fasttimo) { - tmp_time = (200 - (curtime - time_fasttimo)) * 1000; - if (tmp_time < 0) - tmp_time = 0; - - /* Choose the smallest of the 2 */ - if (tmp_time < timeout.tv_usec) - timeout.tv_usec = (u_int)tmp_time; - } - } - - /* - * now, the proxified sockets - */ - proxy_manager_select_fill(&nfds, readfds, writefds, xfds); - - *pnfds = nfds; -} - -void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) -{ - struct socket *so, *so_next; - int ret; - - global_readfds = readfds; - global_writefds = writefds; - global_xfds = xfds; - - /* Update time */ - updtime(); - - /* - * See if anything has timed out - */ - if (link_up) { - if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) { - tcp_fasttimo(); - time_fasttimo = 0; - } - if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) { - ip_slowtimo(); - tcp_slowtimo(); - last_slowtimo = curtime; - } - } - - /* - * Check sockets - */ - if (link_up) { - /* - * Check TCP sockets - */ - for (so = tcb.so_next; so != &tcb; so = so_next) { - so_next = so->so_next; - - /* - * FD_ISSET is meaningless on these sockets - * (and they can crash the program) - */ - if (so->so_state & SS_NOFDREF || so->s == -1) - continue; - - /* - * proxified sockets are polled later in this - * function. - */ - if ((so->so_state & SS_PROXIFIED) != 0) - continue; - - /* - * Check for URG data - * This will soread as well, so no need to - * test for readfds below if this succeeds - */ - if (FD_ISSET(so->s, xfds)) - sorecvoob(so); - /* - * Check sockets for reading - */ - else if (FD_ISSET(so->s, readfds)) { - /* - * Check for incoming connections - */ - if (so->so_state & SS_FACCEPTCONN) { - tcp_connect(so); - continue; - } /* else */ - ret = soread(so); - - /* Output it if we read something */ - if (ret > 0) - tcp_output(sototcpcb(so)); - } - - /* - * Check sockets for writing - */ - if (FD_ISSET(so->s, writefds)) { - /* - * Check for non-blocking, still-connecting sockets - */ - if (so->so_state & SS_ISFCONNECTING) { - /* Connected */ - so->so_state &= ~SS_ISFCONNECTING; - - ret = send(so->s, (char*)&ret, 0, 0); - if (ret < 0) { - /* XXXXX Must fix, zero bytes is a NOP */ - if (errno == EAGAIN || errno == EWOULDBLOCK || - errno == EINPROGRESS || errno == ENOTCONN) - continue; - - /* else failed */ - so->so_state = SS_NOFDREF; - } - /* else so->so_state &= ~SS_ISFCONNECTING; */ - - /* - * Continue tcp_input - */ - tcp_input((MBuf )NULL, sizeof(struct ip), so); - /* continue; */ - } else - ret = sowrite(so); - /* - * XXXXX If we wrote something (a lot), there - * could be a need for a window update. - * In the worst case, the remote will send - * a window probe to get things going again - */ - } - - /* - * Probe a still-connecting, non-blocking socket - * to check if it's still alive - */ -#ifdef PROBE_CONN - if (so->so_state & SS_ISFCONNECTING) { - ret = recv(so->s, (char *)&ret, 0,0); - - if (ret < 0) { - /* XXX */ - if (errno == EAGAIN || errno == EWOULDBLOCK || - errno == EINPROGRESS || errno == ENOTCONN) - continue; /* Still connecting, continue */ - - /* else failed */ - so->so_state = SS_NOFDREF; - - /* tcp_input will take care of it */ - } else { - ret = send(so->s, &ret, 0,0); - if (ret < 0) { - /* XXX */ - if (errno == EAGAIN || errno == EWOULDBLOCK || - errno == EINPROGRESS || errno == ENOTCONN) - continue; - /* else failed */ - so->so_state = SS_NOFDREF; - } else - so->so_state &= ~SS_ISFCONNECTING; - - } - tcp_input((MBuf )NULL, sizeof(struct ip),so); - } /* SS_ISFCONNECTING */ -#endif - } - - /* - * Now UDP sockets. - * Incoming packets are sent straight away, they're not buffered. - * Incoming UDP data isn't buffered either. - */ - for (so = udb.so_next; so != &udb; so = so_next) { - so_next = so->so_next; - - if ((so->so_state & SS_PROXIFIED) != 0) - continue; - - if (so->s != -1 && FD_ISSET(so->s, readfds)) { - sorecvfrom(so); - } - } - } - - /* - * Now the proxified sockets - */ - proxy_manager_poll(readfds, writefds, xfds); - - /* - * See if we can start outputting - */ - if (if_queued && link_up) - if_start(); - - /* clear global file descriptor sets. - * these reside on the stack in vl.c - * so they're unusable if we're not in - * slirp_select_fill or slirp_select_poll. - */ - global_readfds = NULL; - global_writefds = NULL; - global_xfds = NULL; -} - -#define ETH_ALEN 6 -#define ETH_HLEN 14 - -#define ETH_P_IP 0x0800 /* Internet Protocol packet */ -#define ETH_P_ARP 0x0806 /* Address Resolution packet */ - -#define ARPOP_REQUEST 1 /* ARP request */ -#define ARPOP_REPLY 2 /* ARP reply */ - -struct ethhdr -{ - unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ - unsigned char h_source[ETH_ALEN]; /* source ether addr */ - unsigned short h_proto; /* packet type ID field */ -}; - -struct arphdr -{ - unsigned short ar_hrd; /* format of hardware address */ - unsigned short ar_pro; /* format of protocol address */ - unsigned char ar_hln; /* length of hardware address */ - unsigned char ar_pln; /* length of protocol address */ - unsigned short ar_op; /* ARP opcode (command) */ - - /* - * Ethernet looks like this : This bit is variable sized however... - */ - unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ - unsigned char ar_sip[4]; /* sender IP address */ - unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ - unsigned char ar_tip[4]; /* target IP address */ -}; - -void arp_input(const uint8_t *pkt, int pkt_len) -{ - struct ethhdr *eh = (struct ethhdr *)pkt; - struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN); - uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)]; - struct ethhdr *reh = (struct ethhdr *)arp_reply; - struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN); - int ar_op; - - ar_op = ntohs(ah->ar_op); - switch(ar_op) { - case ARPOP_REQUEST: - if (!memcmp(ah->ar_tip, &special_addr, 3)) { - if ( CTL_IS_DNS(ah->ar_tip[3]) || ah->ar_tip[3] == CTL_ALIAS) - goto arp_ok; - return; - arp_ok: - /* XXX: make an ARP request to have the client address */ - memcpy(client_ethaddr, eh->h_source, ETH_ALEN); - - /* ARP request for alias/dns mac address */ - memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN); - memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1); - reh->h_source[5] = ah->ar_tip[3]; - reh->h_proto = htons(ETH_P_ARP); - - rah->ar_hrd = htons(1); - rah->ar_pro = htons(ETH_P_IP); - rah->ar_hln = ETH_ALEN; - rah->ar_pln = 4; - rah->ar_op = htons(ARPOP_REPLY); - memcpy(rah->ar_sha, reh->h_source, ETH_ALEN); - memcpy(rah->ar_sip, ah->ar_tip, 4); - memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN); - memcpy(rah->ar_tip, ah->ar_sip, 4); - slirp_output(arp_reply, sizeof(arp_reply)); - } - break; - default: - break; - } -} - -void slirp_input(const uint8_t *pkt, int pkt_len) -{ - MBuf m; - int proto; - - if (pkt_len < ETH_HLEN) - return; - - proto = ntohs(*(uint16_t *)(pkt + 12)); - switch(proto) { - case ETH_P_ARP: - arp_input(pkt, pkt_len); - break; - case ETH_P_IP: - m = mbuf_alloc(); - if (!m) - return; - /* Note: we add to align the IP header */ - m->m_len = pkt_len + 2; - memcpy(m->m_data + 2, pkt, pkt_len); - - m->m_data += 2 + ETH_HLEN; - m->m_len -= 2 + ETH_HLEN; - - ip_input(m); - break; - default: - break; - } -} - -/* output the IP packet to the ethernet device */ -void if_encap(const uint8_t *ip_data, int ip_data_len) -{ - uint8_t buf[1600]; - struct ethhdr *eh = (struct ethhdr *)buf; - - if (ip_data_len + ETH_HLEN > sizeof(buf)) - return; - - memcpy(eh->h_dest, client_ethaddr, ETH_ALEN); - memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1); - /* XXX: not correct */ - eh->h_source[5] = CTL_ALIAS; - eh->h_proto = htons(ETH_P_IP); - memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len); - slirp_output(buf, ip_data_len + ETH_HLEN); -} - -int slirp_redir(int is_udp, int host_port, - struct in_addr guest_addr, int guest_port) -{ - if (is_udp) { - if (!udp_listen(htons(host_port), guest_addr.s_addr, - htons(guest_port), 0)) - return -1; - } else { - if (!solisten(htons(host_port), guest_addr.s_addr, - htons(guest_port), 0)) - return -1; - } - return 0; -} - -int slirp_unredir(int is_udp, int host_port) -{ - if (is_udp) - return udp_unlisten( host_port ); - else - return sounlisten( host_port ); -} - |