From a13a4126c8b94355bbe43e47275b97ce5bef003c Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Wed, 24 Jun 2009 14:42:28 +0200 Subject: slirp: Rework internal configuration The user mode IP stack is currently only minimally configurable /wrt to its virtual IP addresses. This is unfortunate if some guest has a fixed idea of which IP addresses to use. Therefore this patch prepares the stack for fully configurable IP addresses and masks. The user interface and default addresses remain untouched in this step, they will be enhanced in the following patch. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- slirp/slirp.c | 142 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 83 insertions(+), 59 deletions(-) (limited to 'slirp/slirp.c') diff --git a/slirp/slirp.c b/slirp/slirp.c index b0a092c..8affd46 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; -- cgit v1.1