Commit 3c6a05803c8f33b2ce6f704df87c98983029befd

Authored by Jan Kiszka
Committed by Anthony Liguori
1 parent f3546deb

slirp: Bind support for host forwarding rules

Extend the hostfwd rule format so that the user can specify on which
host interface qemu should listen for incoming connections. If omitted,
binding will takes place against all interfaces.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
... ... @@ -685,7 +685,8 @@ const char *legacy_tftp_prefix;
685 685 const char *legacy_bootp_filename;
686 686 static VLANClientState *slirp_vc;
687 687  
688   -static void slirp_hostfwd(Monitor *mon, const char *redir_str);
  688 +static void slirp_hostfwd(Monitor *mon, const char *redir_str,
  689 + int legacy_format);
689 690 static void slirp_guestfwd(Monitor *mon, const char *config_str,
690 691 int legacy_format);
691 692  
... ... @@ -846,7 +847,8 @@ static int net_slirp_init(Monitor *mon, VLANState *vlan, const char *model,
846 847 struct slirp_config_str *config = slirp_configs;
847 848  
848 849 if (config->flags & SLIRP_CFG_HOSTFWD) {
849   - slirp_hostfwd(mon, config->str);
  850 + slirp_hostfwd(mon, config->str,
  851 + config->flags & SLIRP_CFG_LEGACY);
850 852 } else {
851 853 slirp_guestfwd(mon, config->str,
852 854 config->flags & SLIRP_CFG_LEGACY);
... ... @@ -871,11 +873,12 @@ static int net_slirp_init(Monitor *mon, VLANState *vlan, const char *model,
871 873 return 0;
872 874 }
873 875  
874   -void net_slirp_hostfwd_remove(Monitor *mon, const char *port_str)
  876 +void net_slirp_hostfwd_remove(Monitor *mon, const char *src_str)
875 877 {
  878 + struct in_addr host_addr = { .s_addr = INADDR_ANY };
876 879 int host_port;
877 880 char buf[256] = "";
878   - const char *p = port_str;
  881 + const char *p = src_str;
879 882 int is_udp = 0;
880 883 int n;
881 884  
... ... @@ -884,7 +887,7 @@ void net_slirp_hostfwd_remove(Monitor *mon, const char *port_str)
884 887 return;
885 888 }
886 889  
887   - if (!port_str || !port_str[0])
  890 + if (!src_str || !src_str[0])
888 891 goto fail_syntax;
889 892  
890 893 get_str_sep(buf, sizeof(buf), &p, ':');
... ... @@ -897,20 +900,29 @@ void net_slirp_hostfwd_remove(Monitor *mon, const char *port_str)
897 900 goto fail_syntax;
898 901 }
899 902  
  903 + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
  904 + goto fail_syntax;
  905 + }
  906 + if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
  907 + goto fail_syntax;
  908 + }
  909 +
900 910 host_port = atoi(p);
901 911  
902   - n = slirp_remove_hostfwd(is_udp, host_port);
  912 + n = slirp_remove_hostfwd(is_udp, host_addr, host_port);
903 913  
904   - monitor_printf(mon, "removed %d host forwarding rules for %s port %d\n",
905   - n, is_udp ? "udp" : "tcp", host_port);
  914 + monitor_printf(mon, "removed %d host forwarding rules for %s\n", n,
  915 + src_str);
906 916 return;
907 917  
908 918 fail_syntax:
909 919 monitor_printf(mon, "invalid format\n");
910 920 }
911 921  
912   -static void slirp_hostfwd(Monitor *mon, const char *redir_str)
  922 +static void slirp_hostfwd(Monitor *mon, const char *redir_str,
  923 + int legacy_format)
913 924 {
  925 + struct in_addr host_addr = { .s_addr = INADDR_ANY };
914 926 struct in_addr guest_addr = { .s_addr = 0 };
915 927 int host_port, guest_port;
916 928 const char *p;
... ... @@ -930,7 +942,16 @@ static void slirp_hostfwd(Monitor *mon, const char *redir_str)
930 942 goto fail_syntax;
931 943 }
932 944  
933   - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
  945 + if (!legacy_format) {
  946 + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
  947 + goto fail_syntax;
  948 + }
  949 + if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
  950 + goto fail_syntax;
  951 + }
  952 + }
  953 +
  954 + if (get_str_sep(buf, sizeof(buf), &p, legacy_format ? ':' : '-') < 0) {
934 955 goto fail_syntax;
935 956 }
936 957 host_port = strtol(buf, &end, 0);
... ... @@ -950,7 +971,8 @@ static void slirp_hostfwd(Monitor *mon, const char *redir_str)
950 971 goto fail_syntax;
951 972 }
952 973  
953   - if (slirp_add_hostfwd(is_udp, host_port, guest_addr, guest_port) < 0) {
  974 + if (slirp_add_hostfwd(is_udp, host_addr, host_port,
  975 + guest_addr, guest_port) < 0) {
954 976 config_error(mon, "could not set up host forwarding rule '%s'\n",
955 977 redir_str);
956 978 }
... ... @@ -967,7 +989,7 @@ void net_slirp_hostfwd_add(Monitor *mon, const char *redir_str)
967 989 return;
968 990 }
969 991  
970   - slirp_hostfwd(mon, redir_str);
  992 + slirp_hostfwd(mon, redir_str, 0);
971 993 }
972 994  
973 995 void net_slirp_redir(const char *redir_str)
... ... @@ -977,13 +999,13 @@ void net_slirp_redir(const char *redir_str)
977 999 if (!slirp_inited) {
978 1000 config = qemu_malloc(sizeof(*config));
979 1001 pstrcpy(config->str, sizeof(config->str), redir_str);
980   - config->flags = SLIRP_CFG_HOSTFWD;
  1002 + config->flags = SLIRP_CFG_HOSTFWD | SLIRP_CFG_LEGACY;
981 1003 config->next = slirp_configs;
982 1004 slirp_configs = config;
983 1005 return;
984 1006 }
985 1007  
986   - slirp_hostfwd(NULL, redir_str);
  1008 + slirp_hostfwd(NULL, redir_str, 1);
987 1009 }
988 1010  
989 1011 #ifndef _WIN32
... ...
... ... @@ -133,7 +133,7 @@ void net_client_uninit(NICInfo *nd);
133 133 int net_client_parse(const char *str);
134 134 void net_slirp_smb(const char *exported_dir);
135 135 void net_slirp_hostfwd_add(Monitor *mon, const char *redir_str);
136   -void net_slirp_hostfwd_remove(Monitor *mon, const char *port_str);
  136 +void net_slirp_hostfwd_remove(Monitor *mon, const char *src_str);
137 137 void net_slirp_redir(const char *redir_str);
138 138 void net_cleanup(void);
139 139 int slirp_is_inited(void);
... ...
qemu-monitor.hx
... ... @@ -537,10 +537,11 @@ ETEXI
537 537  
538 538 #ifdef CONFIG_SLIRP
539 539 { "hostfwd_add", "s", net_slirp_hostfwd_add,
540   - "[tcp|udp]:hostport:[guestaddr]:guestport",
  540 + "[tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport",
541 541 "redirect TCP or UDP connections from host to guest (requires -net user)" },
542 542 { "hostfwd_remove", "s", net_slirp_hostfwd_remove,
543   - "[tcp|udp]:hostport", "remove host-to-guest TCP or UDP redirection" },
  543 + "[tcp|udp]:[hostaddr]:hostport",
  544 + "remove host-to-guest TCP or UDP redirection" },
544 545 #endif
545 546 STEXI
546 547 @item host_net_redir
... ...
qemu-options.hx
... ... @@ -881,11 +881,12 @@ Note that a SAMBA server must be installed on the host OS in
881 881 @file{/usr/sbin/smbd}. QEMU was tested successfully with smbd versions from
882 882 Red Hat 9, Fedora Core 3 and OpenSUSE 11.x.
883 883  
884   -@item hostfwd=[tcp|udp]:@var{hostport}:[@var{guestaddr}]:@var{guestport}
  884 +@item hostfwd=[tcp|udp]:[@var{hostaddr}]:@var{hostport}-[@var{guestaddr}]:@var{guestport}
885 885 Redirect incoming TCP or UDP connections to the host port @var{hostport} to
886 886 the guest IP address @var{guestaddr} on guest port @var{guestport}. If
887 887 @var{guestaddr} is not specified, its value is x.x.x.15 (default first address
888   -given by the built-in DHCP server). If no connection type is specified, TCP is
  888 +given by the built-in DHCP server). By specifying @var{hostaddr}, the rule can
  889 +be bound to a specific host interface. If no connection type is set, TCP is
889 890 used. This option can be given multiple times.
890 891  
891 892 For example, to redirect host X11 connection from screen 1 to guest
... ... @@ -893,7 +894,7 @@ screen 0, use the following:
893 894  
894 895 @example
895 896 # on the host
896   -qemu -net user,hostfwd=tcp:6001::6000 [...]
  897 +qemu -net user,hostfwd=tcp:127.0.0.1:6001-:6000 [...]
897 898 # this host xterm should open in the guest X11 server
898 899 xterm -display :1
899 900 @end example
... ... @@ -911,8 +912,8 @@ Then when you use on the host @code{telnet localhost 5555}, you
911 912 connect to the guest telnet server.
912 913  
913 914 @item guestfwd=[tcp]:@var{server}:@var{port}-@var{dev}
914   -Forward guest TCP connections to port @var{port} on the host to character
915   -device @var{dev}. This option can be given multiple times.
  915 +Forward guest TCP connections to the IP address @var{server} on port @var{port}
  916 +to the character device @var{dev}. This option can be given multiple times.
916 917  
917 918 @end table
918 919  
... ...
slirp/libslirp.h
... ... @@ -22,10 +22,9 @@ void slirp_input(const uint8_t *pkt, int pkt_len);
22 22 int slirp_can_output(void);
23 23 void slirp_output(const uint8_t *pkt, int pkt_len);
24 24  
25   -int slirp_add_hostfwd(int is_udp, int host_port,
  25 +int slirp_add_hostfwd(int is_udp, struct in_addr host_addr, int host_port,
26 26 struct in_addr guest_addr, int guest_port);
27   -int slirp_remove_hostfwd(int is_udp, int host_port);
28   -
  27 +int slirp_remove_hostfwd(int is_udp, struct in_addr host_addr, int host_port);
29 28 int slirp_add_exec(int do_pty, const void *args, struct in_addr guest_addr,
30 29 int guest_port);
31 30  
... ...
slirp/slirp.c
... ... @@ -757,7 +757,7 @@ void if_encap(const uint8_t *ip_data, int ip_data_len)
757 757 /* Unlistens a redirection
758 758 *
759 759 * Return value: number of redirs removed */
760   -int slirp_remove_hostfwd(int is_udp, int host_port)
  760 +int slirp_remove_hostfwd(int is_udp, struct in_addr host_addr, int host_port)
761 761 {
762 762 struct socket *so;
763 763 struct socket *head = (is_udp ? &udb : &tcb);
... ... @@ -770,6 +770,7 @@ int slirp_remove_hostfwd(int is_udp, int host_port)
770 770 for (so = head->so_next; so != head; so = so->so_next) {
771 771 addr_len = sizeof(addr);
772 772 if (getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
  773 + addr.sin_addr.s_addr == host_addr.s_addr &&
773 774 addr.sin_port == port) {
774 775 close(so->s);
775 776 sofree(so);
... ... @@ -781,19 +782,19 @@ int slirp_remove_hostfwd(int is_udp, int host_port)
781 782 return n;
782 783 }
783 784  
784   -int slirp_add_hostfwd(int is_udp, int host_port,
  785 +int slirp_add_hostfwd(int is_udp, struct in_addr host_addr, int host_port,
785 786 struct in_addr guest_addr, int guest_port)
786 787 {
787 788 if (!guest_addr.s_addr) {
788 789 guest_addr = vdhcp_startaddr;
789 790 }
790 791 if (is_udp) {
791   - if (!udp_listen(htons(host_port), guest_addr.s_addr,
  792 + if (!udp_listen(host_addr.s_addr, htons(host_port), guest_addr.s_addr,
792 793 htons(guest_port), 0))
793 794 return -1;
794 795 } else {
795   - if (!solisten(htons(host_port), guest_addr.s_addr,
796   - htons(guest_port), 0))
  796 + if (!tcp_listen(host_addr.s_addr, htons(host_port), guest_addr.s_addr,
  797 + htons(guest_port), 0))
797 798 return -1;
798 799 }
799 800 return 0;
... ...
slirp/socket.c
... ... @@ -586,17 +586,17 @@ sosendto(struct socket *so, struct mbuf *m)
586 586 }
587 587  
588 588 /*
589   - * XXX This should really be tcp_listen
  589 + * Listen for incoming TCP connections
590 590 */
591 591 struct socket *
592   -solisten(u_int port, u_int32_t laddr, u_int lport, int flags)
  592 +tcp_listen(u_int32_t haddr, u_int hport, u_int32_t laddr, u_int lport, int flags)
593 593 {
594 594 struct sockaddr_in addr;
595 595 struct socket *so;
596 596 int s, opt = 1;
597 597 socklen_t addrlen = sizeof(addr);
598 598  
599   - DEBUG_CALL("solisten");
  599 + DEBUG_CALL("tcp_listen");
600 600 DEBUG_ARG("port = %d", port);
601 601 DEBUG_ARG("laddr = %x", laddr);
602 602 DEBUG_ARG("lport = %d", lport);
... ... @@ -625,8 +625,8 @@ solisten(u_int port, u_int32_t laddr, u_int lport, int flags)
625 625 so->so_laddr.s_addr = laddr; /* Ditto */
626 626  
627 627 addr.sin_family = AF_INET;
628   - addr.sin_addr.s_addr = INADDR_ANY;
629   - addr.sin_port = port;
  628 + addr.sin_addr.s_addr = haddr;
  629 + addr.sin_port = hport;
630 630  
631 631 if (((s = socket(AF_INET,SOCK_STREAM,0)) < 0) ||
632 632 (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) ||
... ...
slirp/socket.h
... ... @@ -82,7 +82,7 @@ int sosendoob _P((struct socket *));
82 82 int sowrite _P((struct socket *));
83 83 void sorecvfrom _P((struct socket *));
84 84 int sosendto _P((struct socket *, struct mbuf *));
85   -struct socket * solisten _P((u_int, u_int32_t, u_int, int));
  85 +struct socket * tcp_listen _P((u_int32_t, u_int, u_int32_t, u_int, int));
86 86 void soisfconnecting _P((register struct socket *));
87 87 void soisfconnected _P((register struct socket *));
88 88 void soisfdisconnected _P((struct socket *));
... ...
slirp/tcp_subr.c
... ... @@ -970,7 +970,7 @@ do_prompt:
970 970 laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
971 971 lport = htons((n5 << 8) | (n6));
972 972  
973   - if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL)
  973 + if ((so = tcp_listen(INADDR_ANY, 0, laddr, lport, SS_FACCEPTONCE)) == NULL)
974 974 return 1;
975 975  
976 976 n6 = ntohs(so->so_fport);
... ... @@ -1002,7 +1002,7 @@ do_prompt:
1002 1002 laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
1003 1003 lport = htons((n5 << 8) | (n6));
1004 1004  
1005   - if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL)
  1005 + if ((so = tcp_listen(INADDR_ANY, 0, laddr, lport, SS_FACCEPTONCE)) == NULL)
1006 1006 return 1;
1007 1007  
1008 1008 n6 = ntohs(so->so_fport);
... ... @@ -1042,7 +1042,7 @@ do_prompt:
1042 1042 lport += m->m_data[i] - '0';
1043 1043 }
1044 1044 if (m->m_data[m->m_len-1] == '\0' && lport != 0 &&
1045   - (so = solisten(0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL)
  1045 + (so = tcp_listen(INADDR_ANY, 0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL)
1046 1046 m->m_len = snprintf(m->m_data, m->m_hdr.mh_size, "%d",
1047 1047 ntohs(so->so_fport)) + 1;
1048 1048 return 1;
... ... @@ -1057,7 +1057,7 @@ do_prompt:
1057 1057  
1058 1058 /* The %256s is for the broken mIRC */
1059 1059 if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) {
1060   - if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
  1060 + if ((so = tcp_listen(INADDR_ANY, 0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
1061 1061 return 1;
1062 1062  
1063 1063 m->m_len = bptr - m->m_data; /* Adjust length */
... ... @@ -1066,7 +1066,7 @@ do_prompt:
1066 1066 (unsigned long)ntohl(so->so_faddr.s_addr),
1067 1067 ntohs(so->so_fport), 1);
1068 1068 } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
1069   - if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
  1069 + if ((so = tcp_listen(INADDR_ANY, 0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
1070 1070 return 1;
1071 1071  
1072 1072 m->m_len = bptr - m->m_data; /* Adjust length */
... ... @@ -1075,7 +1075,7 @@ do_prompt:
1075 1075 (unsigned long)ntohl(so->so_faddr.s_addr),
1076 1076 ntohs(so->so_fport), n1, 1);
1077 1077 } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
1078   - if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
  1078 + if ((so = tcp_listen(INADDR_ANY, 0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
1079 1079 return 1;
1080 1080  
1081 1081 m->m_len = bptr - m->m_data; /* Adjust length */
... ... @@ -1190,7 +1190,8 @@ do_prompt:
1190 1190  
1191 1191 /* try to get udp port between 6970 - 7170 */
1192 1192 for (p = 6970; p < 7071; p++) {
1193   - if (udp_listen( htons(p),
  1193 + if (udp_listen(INADDR_ANY,
  1194 + htons(p),
1194 1195 so->so_laddr.s_addr,
1195 1196 htons(lport),
1196 1197 SS_FACCEPTONCE)) {
... ...
slirp/udp.c
... ... @@ -627,7 +627,8 @@ struct cu_header {
627 627 }
628 628  
629 629 struct socket *
630   -udp_listen(u_int port, u_int32_t laddr, u_int lport, int flags)
  630 +udp_listen(u_int32_t haddr, u_int hport, u_int32_t laddr, u_int lport,
  631 + int flags)
631 632 {
632 633 struct sockaddr_in addr;
633 634 struct socket *so;
... ... @@ -642,8 +643,8 @@ udp_listen(u_int port, u_int32_t laddr, u_int lport, int flags)
642 643 insque(so,&udb);
643 644  
644 645 addr.sin_family = AF_INET;
645   - addr.sin_addr.s_addr = INADDR_ANY;
646   - addr.sin_port = port;
  646 + addr.sin_addr.s_addr = haddr;
  647 + addr.sin_port = hport;
647 648  
648 649 if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) {
649 650 udp_detach(so);
... ...
slirp/udp.h
... ... @@ -101,7 +101,7 @@ void udp_input _P((register struct mbuf *, int));
101 101 int udp_output _P((struct socket *, struct mbuf *, struct sockaddr_in *));
102 102 int udp_attach _P((struct socket *));
103 103 void udp_detach _P((struct socket *));
104   -struct socket * udp_listen _P((u_int, u_int32_t, u_int, int));
  104 +struct socket * udp_listen _P((u_int32_t, u_int, u_int32_t, u_int, int));
105 105 int udp_output2(struct socket *so, struct mbuf *m,
106 106 struct sockaddr_in *saddr, struct sockaddr_in *daddr,
107 107 int iptos);
... ...