diff options
Diffstat (limited to 'slirp/slirp.c')
-rw-r--r-- | slirp/slirp.c | 142 |
1 files changed, 83 insertions, 59 deletions
diff --git a/slirp/slirp.c b/slirp/slirp.c index b0a092c14c..8affd46c7c 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -33,13 +33,16 @@ struct in_addr dns_addr; /* 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; - +/* virtual network configuration */ +struct in_addr vnetwork_addr; +struct in_addr vnetwork_mask; +struct in_addr vhost_addr; +struct in_addr vdhcp_startaddr; +struct in_addr vnameserver_addr; + +/* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */ static const uint8_t special_ethaddr[6] = { - 0x52, 0x54, 0x00, 0x12, 0x35, 0x00 + 0x52, 0x55, 0x00, 0x00, 0x00, 0x00 }; /* ARP cache for the guest IP addresses (XXX: allow many entries) */ @@ -48,7 +51,6 @@ static struct in_addr client_ipaddr; static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 }; -const char *slirp_special_ip = CTL_SPECIAL; int slirp_restrict; static int do_slowtimo; int link_up; @@ -176,12 +178,12 @@ void slirp_init(int restricted, const char *special_ip, const char *tftp_path, { // debug_init("/tmp/slirp.log", DEBUG_DEFAULT); + struct in_addr special_addr = { .s_addr = htonl(0x0a000200) }; #ifdef _WIN32 - { - WSADATA Data; - WSAStartup(MAKEWORD(2,0), &Data); - atexit(slirp_cleanup); - } + WSADATA Data; + + WSAStartup(MAKEWORD(2,0), &Data); + atexit(slirp_cleanup); #endif link_up = 1; @@ -201,9 +203,9 @@ void slirp_init(int restricted, const char *special_ip, const char *tftp_path, fprintf (stderr, "Warning: No DNS servers found\n"); } - if (special_ip) - slirp_special_ip = special_ip; - + if (special_ip) { + inet_aton(special_ip, &special_addr); + } qemu_free(tftp_prefix); tftp_prefix = NULL; if (tftp_path) { @@ -215,8 +217,11 @@ void slirp_init(int restricted, const char *special_ip, const char *tftp_path, bootp_filename = qemu_strdup(bootfile); } - inet_aton(slirp_special_ip, &special_addr); - alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS); + vnetwork_addr = special_addr; + vnetwork_mask.s_addr = htonl(0xffffff00); + vhost_addr.s_addr = special_addr.s_addr | htonl(2); + vdhcp_startaddr.s_addr = special_addr.s_addr | htonl(15); + vnameserver_addr.s_addr = special_addr.s_addr | htonl(3); getouraddr(); register_savevm("slirp", 0, 1, slirp_state_save, slirp_state_load, NULL); } @@ -601,10 +606,10 @@ struct arphdr * 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 */ + uint32_t ar_sip; /* sender IP address */ unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ - unsigned char ar_tip[4]; /* target IP address */ -}; + uint32_t ar_tip ; /* target IP address */ +} __attribute__((packed)); static void arp_input(const uint8_t *pkt, int pkt_len) { @@ -619,11 +624,12 @@ static void arp_input(const uint8_t *pkt, int pkt_len) ar_op = ntohs(ah->ar_op); switch(ar_op) { case ARPOP_REQUEST: - if (!memcmp(ah->ar_tip, &special_addr, 3)) { - if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS) + if ((ah->ar_tip & vnetwork_mask.s_addr) == vnetwork_addr.s_addr) { + if (ah->ar_tip == vnameserver_addr.s_addr || + ah->ar_tip == vhost_addr.s_addr) goto arp_ok; for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { - if (ex_ptr->ex_addr == ah->ar_tip[3]) + if (ex_ptr->ex_addr.s_addr == ah->ar_tip) goto arp_ok; } return; @@ -633,8 +639,8 @@ static void arp_input(const uint8_t *pkt, int pkt_len) /* 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]; + memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4); + memcpy(&reh->h_source[2], &ah->ar_tip, 4); reh->h_proto = htons(ETH_P_ARP); rah->ar_hrd = htons(1); @@ -643,16 +649,16 @@ static void arp_input(const uint8_t *pkt, int pkt_len) 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); + rah->ar_sip = ah->ar_tip; memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN); - memcpy(rah->ar_tip, ah->ar_sip, 4); + rah->ar_tip = ah->ar_sip; slirp_output(arp_reply, sizeof(arp_reply)); } break; case ARPOP_REPLY: /* reply to request of client mac address ? */ if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN) && - !memcmp(ah->ar_sip, &client_ipaddr.s_addr, 4)) { + ah->ar_sip == client_ipaddr.s_addr) { memcpy(client_ethaddr, ah->ar_sha, ETH_ALEN); } break; @@ -716,8 +722,8 @@ void if_encap(const uint8_t *ip_data, int ip_data_len) in place of sending the packet and we hope that the sender will retry sending its packet. */ memset(reh->h_dest, 0xff, ETH_ALEN); - memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1); - reh->h_source[5] = CTL_ALIAS; + memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4); + memcpy(&reh->h_source[2], &vhost_addr, 4); reh->h_proto = htons(ETH_P_ARP); rah->ar_hrd = htons(1); rah->ar_pro = htons(ETH_P_IP); @@ -725,21 +731,21 @@ void if_encap(const uint8_t *ip_data, int ip_data_len) rah->ar_pln = 4; rah->ar_op = htons(ARPOP_REQUEST); /* source hw addr */ - memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 1); - rah->ar_sha[5] = CTL_ALIAS; + memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4); + memcpy(&rah->ar_sha[2], &vhost_addr, 4); /* source IP */ - memcpy(rah->ar_sip, &alias_addr, 4); + rah->ar_sip = vhost_addr.s_addr; /* target hw addr (none) */ memset(rah->ar_tha, 0, ETH_ALEN); /* target IP */ - memcpy(rah->ar_tip, &iph->ip_dst, 4); + rah->ar_tip = iph->ip_dst.s_addr; client_ipaddr = iph->ip_dst; slirp_output(arp_req, sizeof(arp_req)); } else { memcpy(eh->h_dest, client_ethaddr, ETH_ALEN); - memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1); + memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4); /* XXX: not correct */ - eh->h_source[5] = CTL_ALIAS; + memcpy(&eh->h_source[2], &vhost_addr, 4); 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); @@ -772,6 +778,9 @@ int slirp_redir_rm(int is_udp, int host_port) int slirp_redir(int is_udp, int host_port, struct in_addr guest_addr, int guest_port) { + if (!guest_addr.s_addr) { + guest_addr = vdhcp_startaddr; + } if (is_udp) { if (!udp_listen(htons(host_port), guest_addr.s_addr, htons(guest_port), 0)) @@ -787,8 +796,17 @@ int slirp_redir(int is_udp, int host_port, int slirp_add_exec(int do_pty, const void *args, int addr_low_byte, int guest_port) { - return add_exec(&exec_list, do_pty, (char *)args, - addr_low_byte, htons(guest_port)); + struct in_addr guest_addr = { + .s_addr = vnetwork_addr.s_addr | htonl(addr_low_byte) + }; + + if ((guest_addr.s_addr & vnetwork_mask.s_addr) != vnetwork_addr.s_addr || + guest_addr.s_addr == vhost_addr.s_addr || + guest_addr.s_addr == vnameserver_addr.s_addr) { + return -1; + } + return add_exec(&exec_list, do_pty, (char *)args, guest_addr, + htons(guest_port)); } ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags) @@ -801,31 +819,32 @@ ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags) return send(so->s, buf, len, flags); } -static struct socket *slirp_find_ctl_socket(int addr_low_byte, int guest_port) +static struct socket * +slirp_find_ctl_socket(struct in_addr guest_addr, int guest_port) { - struct socket *so; - - for (so = tcb.so_next; so != &tcb; so = so->so_next) { - if ((so->so_faddr.s_addr & htonl(0xffffff00)) == - special_addr.s_addr - && (ntohl(so->so_faddr.s_addr) & 0xff) == - addr_low_byte - && htons(so->so_fport) == guest_port) - return so; - } + struct socket *so; - return NULL; + for (so = tcb.so_next; so != &tcb; so = so->so_next) { + if (so->so_faddr.s_addr == guest_addr.s_addr && + htons(so->so_fport) == guest_port) { + return so; + } + } + return NULL; } size_t slirp_socket_can_recv(int addr_low_byte, int guest_port) { + struct in_addr guest_addr = { + .s_addr = vnetwork_addr.s_addr | htonl(addr_low_byte) + }; struct iovec iov[2]; struct socket *so; if (!link_up) return 0; - so = slirp_find_ctl_socket(addr_low_byte, guest_port); + so = slirp_find_ctl_socket(guest_addr, guest_port); if (!so || so->so_state & SS_NOFDREF) return 0; @@ -840,8 +859,11 @@ void slirp_socket_recv(int addr_low_byte, int guest_port, const uint8_t *buf, int size) { int ret; - struct socket *so = slirp_find_ctl_socket(addr_low_byte, guest_port); - + struct in_addr guest_addr = { + .s_addr = vnetwork_addr.s_addr | htonl(addr_low_byte) + }; + struct socket *so = slirp_find_ctl_socket(guest_addr, guest_port); + if (!so) return; @@ -1055,15 +1077,17 @@ static int slirp_state_load(QEMUFile *f, void *opaque, int version_id) if (ret < 0) return ret; - if ((so->so_faddr.s_addr & htonl(0xffffff00)) != special_addr.s_addr) + if ((so->so_faddr.s_addr & vnetwork_mask.s_addr) != + vnetwork_addr.s_addr) { return -EINVAL; - - for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) + } + for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { if (ex_ptr->ex_pty == 3 && - (ntohl(so->so_faddr.s_addr) & 0xff) == ex_ptr->ex_addr && - so->so_fport == ex_ptr->ex_fport) + so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr && + so->so_fport == ex_ptr->ex_fport) { break; - + } + } if (!ex_ptr) return -EINVAL; |