summaryrefslogtreecommitdiff
path: root/src/usr.bin/nc/socks.c
diff options
context:
space:
mode:
authordjm <>2006-01-25 23:21:37 +0000
committerdjm <>2006-01-25 23:21:37 +0000
commit9a4d7f3f204beeffd203f2d34f204cc19d7321e4 (patch)
tree35b595e90f1ecf05250205412afa830537e2371f /src/usr.bin/nc/socks.c
parentf9006c0d860615bd798c2a8b553ba592ec3b4524 (diff)
downloadopenbsd-9a4d7f3f204beeffd203f2d34f204cc19d7321e4.tar.gz
openbsd-9a4d7f3f204beeffd203f2d34f204cc19d7321e4.tar.bz2
openbsd-9a4d7f3f204beeffd203f2d34f204cc19d7321e4.zip
implement HTTP proxy authentication support, very useful in a ssh_config
ProxyCommand; ok beck@
Diffstat (limited to 'src/usr.bin/nc/socks.c')
-rw-r--r--src/usr.bin/nc/socks.c89
1 files changed, 72 insertions, 17 deletions
diff --git a/src/usr.bin/nc/socks.c b/src/usr.bin/nc/socks.c
index de61439400..daed99712e 100644
--- a/src/usr.bin/nc/socks.c
+++ b/src/usr.bin/nc/socks.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: socks.c,v 1.15 2005/05/24 20:13:28 avsm Exp $ */ 1/* $OpenBSD: socks.c,v 1.16 2006/01/25 23:21:37 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1999 Niklas Hallqvist. All rights reserved. 4 * Copyright (c) 1999 Niklas Hallqvist. All rights reserved.
@@ -37,6 +37,8 @@
37#include <stdlib.h> 37#include <stdlib.h>
38#include <string.h> 38#include <string.h>
39#include <unistd.h> 39#include <unistd.h>
40#include <resolv.h>
41#include <readpassphrase.h>
40#include "atomicio.h" 42#include "atomicio.h"
41 43
42#define SOCKS_PORT "1080" 44#define SOCKS_PORT "1080"
@@ -52,9 +54,9 @@
52#define SOCKS_IPV6 4 54#define SOCKS_IPV6 4
53 55
54int remote_connect(const char *, const char *, struct addrinfo); 56int remote_connect(const char *, const char *, struct addrinfo);
55int socks_connect(const char *host, const char *port, struct addrinfo hints, 57int socks_connect(const char *, const char *, struct addrinfo,
56 const char *proxyhost, const char *proxyport, struct addrinfo proxyhints, 58 const char *, const char *, struct addrinfo, int,
57 int socksv); 59 const char *);
58 60
59static int 61static int
60decode_addrport(const char *h, const char *p, struct sockaddr *addr, 62decode_addrport(const char *h, const char *p, struct sockaddr *addr,
@@ -107,13 +109,26 @@ proxy_read_line(int fd, char *buf, size_t bufsz)
107 return (off); 109 return (off);
108} 110}
109 111
112static const char *
113getproxypass(const char *proxyuser, const char *proxyhost)
114{
115 char prompt[512];
116 static char pw[256];
117
118 snprintf(prompt, sizeof(prompt), "Proxy password for %s@%s: ",
119 proxyuser, proxyhost);
120 if (readpassphrase(prompt, pw, sizeof(pw), RPP_REQUIRE_TTY) == NULL)
121 errx(1, "Unable to read proxy passphrase");
122 return (pw);
123}
124
110int 125int
111socks_connect(const char *host, const char *port, 126socks_connect(const char *host, const char *port,
112 struct addrinfo hints __attribute__ ((__unused__)), 127 struct addrinfo hints __attribute__ ((__unused__)),
113 const char *proxyhost, const char *proxyport, struct addrinfo proxyhints, 128 const char *proxyhost, const char *proxyport, struct addrinfo proxyhints,
114 int socksv) 129 int socksv, const char *proxyuser)
115{ 130{
116 int proxyfd, r; 131 int proxyfd, r, authretry = 0;
117 size_t hlen, wlen; 132 size_t hlen, wlen;
118 unsigned char buf[1024]; 133 unsigned char buf[1024];
119 size_t cnt; 134 size_t cnt;
@@ -121,21 +136,26 @@ socks_connect(const char *host, const char *port,
121 struct sockaddr_in *in4 = (struct sockaddr_in *)&addr; 136 struct sockaddr_in *in4 = (struct sockaddr_in *)&addr;
122 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr; 137 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr;
123 in_port_t serverport; 138 in_port_t serverport;
139 const char *proxypass = NULL;
124 140
125 if (proxyport == NULL) 141 if (proxyport == NULL)
126 proxyport = (socksv == -1) ? HTTP_PROXY_PORT : SOCKS_PORT; 142 proxyport = (socksv == -1) ? HTTP_PROXY_PORT : SOCKS_PORT;
127 143
128 proxyfd = remote_connect(proxyhost, proxyport, proxyhints);
129
130 if (proxyfd < 0)
131 return (-1);
132
133 /* Abuse API to lookup port */ 144 /* Abuse API to lookup port */
134 if (decode_addrport("0.0.0.0", port, (struct sockaddr *)&addr, 145 if (decode_addrport("0.0.0.0", port, (struct sockaddr *)&addr,
135 sizeof(addr), 1, 1) == -1) 146 sizeof(addr), 1, 1) == -1)
136 errx(1, "unknown port \"%.64s\"", port); 147 errx(1, "unknown port \"%.64s\"", port);
137 serverport = in4->sin_port; 148 serverport = in4->sin_port;
138 149
150 again:
151 if (authretry++ > 3)
152 errx(1, "Too many authentication failures");
153
154 proxyfd = remote_connect(proxyhost, proxyport, proxyhints);
155
156 if (proxyfd < 0)
157 return (-1);
158
139 if (socksv == 5) { 159 if (socksv == 5) {
140 if (decode_addrport(host, port, (struct sockaddr *)&addr, 160 if (decode_addrport(host, port, (struct sockaddr *)&addr,
141 sizeof(addr), 0, 1) == -1) 161 sizeof(addr), 0, 1) == -1)
@@ -239,11 +259,11 @@ socks_connect(const char *host, const char *port,
239 /* Try to be sane about numeric IPv6 addresses */ 259 /* Try to be sane about numeric IPv6 addresses */
240 if (strchr(host, ':') != NULL) { 260 if (strchr(host, ':') != NULL) {
241 r = snprintf(buf, sizeof(buf), 261 r = snprintf(buf, sizeof(buf),
242 "CONNECT [%s]:%d HTTP/1.0\r\n\r\n", 262 "CONNECT [%s]:%d HTTP/1.0\r\n",
243 host, ntohs(serverport)); 263 host, ntohs(serverport));
244 } else { 264 } else {
245 r = snprintf(buf, sizeof(buf), 265 r = snprintf(buf, sizeof(buf),
246 "CONNECT %s:%d HTTP/1.0\r\n\r\n", 266 "CONNECT %s:%d HTTP/1.0\r\n",
247 host, ntohs(serverport)); 267 host, ntohs(serverport));
248 } 268 }
249 if (r == -1 || (size_t)r >= sizeof(buf)) 269 if (r == -1 || (size_t)r >= sizeof(buf))
@@ -254,15 +274,50 @@ socks_connect(const char *host, const char *port,
254 if (cnt != r) 274 if (cnt != r)
255 err(1, "write failed (%d/%d)", cnt, r); 275 err(1, "write failed (%d/%d)", cnt, r);
256 276
257 /* Read reply */ 277 if (authretry > 1) {
278 char resp[1024];
279
280 proxypass = getproxypass(proxyuser, proxyhost);
281 r = snprintf(buf, sizeof(buf), "%s:%s",
282 proxyuser, proxypass);
283 if (r == -1 || (size_t)r >= sizeof(buf) ||
284 b64_ntop(buf, strlen(buf), resp,
285 sizeof(resp)) == -1)
286 errx(1, "Proxy username/password too long");
287 r = snprintf(buf, sizeof(buf), "Proxy-Authorization: "
288 "Basic %s\r\n", resp);
289 if (r == -1 || (size_t)r >= sizeof(buf))
290 errx(1, "Proxy auth response too long");
291 r = strlen(buf);
292 if ((cnt = atomicio(vwrite, proxyfd, buf, r)) != r)
293 err(1, "write failed (%d/%d)", cnt, r);
294 }
295
296 /* Terminate headers */
297 if ((r = atomicio(vwrite, proxyfd, "\r\n", 2)) != 2)
298 err(1, "write failed (2/%d)", r);
299
300 /* Read status reply */
301 proxy_read_line(proxyfd, buf, sizeof(buf));
302 if (proxyuser != NULL &&
303 strncmp(buf, "HTTP/1.0 407 ", 12) == 0) {
304 if (authretry > 1) {
305 fprintf(stderr, "Proxy authentication "
306 "failed\n");
307 }
308 close(proxyfd);
309 goto again;
310 } else if (strncmp(buf, "HTTP/1.0 200 ", 12) != 0)
311 errx(1, "Proxy error: \"%s\"", buf);
312
313 /* Headers continue until we hit an empty line */
258 for (r = 0; r < HTTP_MAXHDRS; r++) { 314 for (r = 0; r < HTTP_MAXHDRS; r++) {
259 proxy_read_line(proxyfd, buf, sizeof(buf)); 315 proxy_read_line(proxyfd, buf, sizeof(buf));
260 if (r == 0 && strncmp(buf, "HTTP/1.0 200 ", 12) != 0)
261 errx(1, "Proxy error: \"%s\"", buf);
262 /* Discard headers until we hit an empty line */
263 if (*buf == '\0') 316 if (*buf == '\0')
264 break; 317 break;
265 } 318 }
319 if (*buf != '\0')
320 errx(1, "Too many proxy headers received");
266 } else 321 } else
267 errx(1, "Unknown proxy protocol %d", socksv); 322 errx(1, "Unknown proxy protocol %d", socksv);
268 323