Le 02/04/2017 à 22:19, Samuel Thibault a écrit : > Hello, Hi,
> Thanks for the patch! > > Laurent Vivier, on mar. 28 mars 2017 21:07:56 +0200, wrote: >> @@ -617,6 +621,10 @@ void slirp_pollfds_poll(GArray *pollfds, int >> select_error) >> * Check sockets for reading >> */ >> else if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) { >> + if (so->so_state & SS_ISFCONNECTING) { >> + socks5_recv(so->s, &so->so_proxy_state); >> + continue; >> + } > > It looks odd to be calling socks5_recv in all cases. Shouldn't this > check for so_proxy_state != 0? > We don't need, because we poll for G_IO_IN in SS_ISFCONNECTING state only if so_proxy_state != 0 (see slirp_pollfds_fill() part) >> @@ -645,11 +653,19 @@ void slirp_pollfds_poll(GArray *pollfds, int >> select_error) >> /* >> * Check for non-blocking, still-connecting sockets >> */ >> - if (so->so_state & SS_ISFCONNECTING) { >> - /* Connected */ >> - so->so_state &= ~SS_ISFCONNECTING; >> >> - ret = send(so->s, (const void *) &ret, 0, 0); >> + if (so->so_state & SS_ISFCONNECTING) { >> + ret = socks5_send(so->s, slirp->proxy_user, > > Ditto. Socks5 and non-socks5 code should be properly separated I guess. The socks5_send() behavior is based on so_proxy_state, and once the proxy is connected all must be as if we don't have a proxy, so it seems logic to interleave it there. >> @@ -1069,6 +1085,48 @@ int slirp_add_exec(Slirp *slirp, int do_pty, const >> void *args, >> htons(guest_port)); >> } >> >> +int slirp_add_proxy(Slirp *slirp, const char *server, int port, >> + const char *user, const char *password) >> +{ >> + int fd; >> + socks5_state_t state; >> + struct sockaddr_storage addr; >> + >> + /* check the connection */ > > Please be a bit more verbose :) For instance: > >> + /* just check that the connection to the socks5 server works with >> the given credentials, and close without doing anything with it. */ > OK > >> diff --git a/slirp/socks5.c b/slirp/socks5.c >> new file mode 100644 >> index 0000000..1c5e071 >> --- /dev/null >> +++ b/slirp/socks5.c >> @@ -0,0 +1,284 @@ >> +/* some parts from nmap/ncat GPLv2 */ > > > One can't just steal code like this. You *have* to copy over the > copyright notice, since there's notably the author information. Sorry, I've been naive... Well, for ncat.h license is 281 lines long (with clarifications and extensions) for 60 lines copied... I think it is better to rewrite this part from the RFC1928. >> +static int socks5_proxy_connect(int fd, const char *server, int port) >> +{ >> + struct sockaddr_in saddr; >> + struct hostent *he; >> + >> + he = gethostbyname(server); >> + if (he == NULL) { >> + errno = EINVAL; >> + return -1; >> + } >> + saddr.sin_family = AF_INET; >> + saddr.sin_addr = *(struct in_addr *)he->h_addr; >> + saddr.sin_port = htons(port); > > Please add a TODO: v6 version OK > >> +static int socks5_recv_authenticate(int fd) >> +{ >> + char socksbuf[2]; >> + if (recv(fd, socksbuf, 2, 0) != 2) { >> + return -1; >> + } >> + if (socksbuf[0] != 1 || socksbuf[1] != 0) { > > These look like magic numbers :) Please document what they represent. OK > >> + int len; >> + >> + memset(&socks5msg, 0, sizeof(socks5msg)); >> + >> + socks5msg.ver = SOCKS5_VERSION; >> + socks5msg.cmd = SOCKS_CONNECT; >> + socks5msg.rsv = 0; > > Please rather set len to 4 here, and increment later on > >> + switch (addr->ss_family) { >> + case AF_INET: { >> + struct sockaddr_in *a = (struct sockaddr_in *)addr; >> + >> + socks5msg.atyp = SOCKS5_ATYP_IPv4; >> + memcpy(socks5msg.dst, &a->sin_addr, sizeof(a->sin_addr)); >> + len = sizeof(a->sin_addr); > > here > >> + memcpy(socks5msg.dst + len, &a->sin_port, sizeof(a->sin_port)); >> + len += sizeof(a->sin_port); >> + } >> + break; >> + case AF_INET6: { >> + struct sockaddr_in6 *a = (struct sockaddr_in6 *)addr; >> + >> + socks5msg.atyp = SOCKS5_ATYP_IPv6; >> + memcpy(socks5msg.dst, &a->sin6_addr, sizeof(a->sin6_addr)); >> + len = sizeof(a->sin6_addr); > > and there. > >> + memcpy(socks5msg.dst + len, &a->sin6_port, >> sizeof(a->sin6_port)); >> + len += sizeof(a->sin6_port); >> + } >> + break; >> + default: >> + errno = EINVAL; >> + return -1; >> + } >> + len += 4; > > and not have this here, where people wonder what that is :) OK > >> +static int socks5_recv_connect(int fd) >> +{ >> + struct socks5_request socks5msg; >> + >> + if (recv(fd, &socks5msg, 4, 0) != 4) { > > Thinking about it (there are more like that above and below). You can > theoretically have a short read here... So please at least leave a note > that we actually should manage buffering of recv()s. OK > >> +++ b/slirp/socks5.h >> +struct socks4_data { >> + char version; >> + char type; >> + unsigned short port; >> + uint32_t address; >> + char data[SOCKS_BUFF_SIZE]; /* to hold FQDN and username */ >> +} __attribute__((packed)); >> + >> +/* SOCKS4 protocol responses */ >> +#define SOCKS4_VERSION 4 >> +#define SOCKS_CONNECT 1 >> +#define SOCKS_BIND 2 >> +#define SOCKS4_CONN_ACC 90 >> +#define SOCKS4_CONN_REF 91 >> +#define SOCKS4_CONN_IDENT 92 >> +#define SOCKS4_CONN_IDENTDIFF 93 > > These are unused, better just drop them? I will rewrite this to avoid copy from ncat. > >> @@ -394,11 +395,21 @@ tcp_sockclosed(struct tcpcb *tp) >> int tcp_fconnect(struct socket *so, unsigned short af) >> { >> int ret=0; >> + Slirp *slirp = so->slirp; >> >> DEBUG_CALL("tcp_fconnect"); >> DEBUG_ARG("so = %p", so); >> >> - ret = so->s = qemu_socket(af, SOCK_STREAM, 0); >> + /* local traffic doesn't go to the proxy */ > > Please fix the comment into "only pass local traffic through the proxy", > to actually reflect what the following "if" does :) > >> + if (slirp->proxy_server && >> + !(af == AF_INET && >> + (so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == >> + slirp->vnetwork_addr.s_addr)) { >> + ret = so->s = socks5_socket(&so->so_proxy_state); > > Please do support AF_INET6 too here, otherwise when working with an ipv6 > host setup it will break. OK > >> diff --git a/slirp/udp6.c b/slirp/udp6.c >> index 9fa314b..995181d 100644 >> --- a/slirp/udp6.c >> +++ b/slirp/udp6.c >> @@ -22,7 +22,7 @@ void udp6_input(struct mbuf *m) >> DEBUG_CALL("udp6_input"); >> DEBUG_ARG("m = %lx", (long)m); >> >> - if (slirp->restricted) { >> + if (slirp->restricted || slirp->proxy_server) { >> goto bad; > > Ditto: please do support ipv6 here. It shouldn't be hard, it should be a > matter of using the same test as v4 :) OK Thanks, Laurent