int privsep_recv(struct io *io, struct msg *msg, struct msgbuf *msgbuf) { char *tmpbuf; if (msgbuf != NULL) { msgbuf->buf = NULL; msgbuf->len = 0; } if (io_wait(io, sizeof *msg, INFTIM, NULL) != 0) return (-1); if (io_read2(io, msg, sizeof *msg) != 0) return (-1); if (msg->size == 0) return (0); if (io_wait(io, msg->size, INFTIM, NULL) != 0) return (-1); if (msgbuf == NULL) { if ((tmpbuf = io_read(io, msg->size)) == NULL) return (-1); xfree(tmpbuf); } else { if ((msgbuf->buf = io_read(io, msg->size)) == NULL) return (-1); msgbuf->len = msg->size; } return (0); }
int socks5proxy(struct server *srv, struct proxy *pr, struct io *io, int timeout, char **cause) { int port, auth; char buf[1024], *ptr; size_t len; if ((port = getport(srv->port)) < 0) { xasprintf(cause, "bad port: %s", srv->port); return (-1); } /* Method selection. */ auth = pr->user != NULL && pr->pass != NULL; buf[0] = 5; buf[1] = auth ? 2 : 1; buf[2] = 0; /* 0 = no auth */ buf[3] = 2; /* 2 = user/pass auth */ io_write(io, buf, auth ? 4 : 3); if (io_wait(io, 2, timeout, cause) != 0) return (-1); io_read2(io, buf, 2); if (buf[0] != 5) { xasprintf(cause, "bad protocol version: %d", buf[0]); return (-1); } if ((buf[1] != 0 && buf[1] != 2) || (auth == 0 && buf[1] == 2)) { xasprintf(cause, "unexpected method: %d", buf[1]); return (-1); } /* User/pass negotiation. */ if (buf[1] == 2) { ptr = buf; *ptr++ = 5; len = strlen(pr->user); if (len > 255) { xasprintf(cause, "user too long"); return (-1); } *ptr++ = len; memcpy(ptr, pr->user, len); ptr += len; len = strlen(pr->pass); if (len > 255) { xasprintf(cause, "pass too long"); return (-1); } *ptr++ = len; memcpy(ptr, pr->pass, len); ptr += len; io_write(io, buf, ptr - buf); if (io_wait(io, 2, timeout, cause) != 0) return (-1); io_read2(io, buf, 2); if (buf[0] != 5) { xasprintf(cause, "bad protocol version: %d", buf[0]); return (-1); } if (buf[1] != 0) { xasprintf(cause, "authentication failed"); return (-1); } } /* Connect request. */ ptr = buf; *ptr++ = 5; *ptr++ = 1; /* 1 = connect */ *ptr++ = 0; /* reserved */ *ptr++ = 3; /* 3 = domain name */ len = strlen(srv->host); if (len > 255) { xasprintf(cause, "host too long"); return (-1); } *ptr++ = len; memcpy(ptr, srv->host, len); ptr += len; *ptr++ = (port >> 8) & 0xff; *ptr++ = port & 0xff; io_write(io, buf, ptr - buf); /* Connect response. */ if (io_wait(io, 5, timeout, cause) != 0) return (-1); io_read2(io, buf, 5); if (buf[0] != 5) { xasprintf(cause, "bad protocol version: %d", buf[0]); return (-1); } switch (buf[1]) { case 0: break; case 1: xasprintf(cause, "%d: server failure", buf[1]); return (-1); case 2: xasprintf(cause, "%d: connection not permitted", buf[1]); return (-1); case 3: xasprintf(cause, "%d: network unreachable", buf[1]); return (-1); case 4: xasprintf(cause, "%d: host unreachable", buf[1]); return (-1); case 5: xasprintf(cause, "%d: connection refused", buf[1]); return (-1); case 6: xasprintf(cause, "%d: TTL expired", buf[1]); return (-1); case 7: xasprintf(cause, "%d: command not supported", buf[1]); return (-1); case 8: xasprintf(cause, "%d: address type not supported", buf[1]); return (-1); default: xasprintf(cause, "%d: unknown failure", buf[1]); return (-1); } /* Flush the rest. */ switch (buf[3]) { case 1: /* IPv4 */ len = 5; break; case 3: /* host */ len = buf[4] + 2; break; case 4: /* IPv6 */ len = 17; break; default: xasprintf(cause, "unknown address type: %d", buf[3]); return (-1); } if (io_wait(io, len, timeout, cause) != 0) return (-1); io_read2(io, buf, len); return (0); }