summaryrefslogtreecommitdiff
path: root/src
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
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')
-rw-r--r--src/usr.bin/nc/nc.113
-rw-r--r--src/usr.bin/nc/netcat.c16
-rw-r--r--src/usr.bin/nc/socks.c89
3 files changed, 95 insertions, 23 deletions
diff --git a/src/usr.bin/nc/nc.1 b/src/usr.bin/nc/nc.1
index 85e18a53f7..2b87caa915 100644
--- a/src/usr.bin/nc/nc.1
+++ b/src/usr.bin/nc/nc.1
@@ -1,4 +1,4 @@
1.\" $OpenBSD: nc.1,v 1.41 2005/10/25 03:51:06 dtucker Exp $ 1.\" $OpenBSD: nc.1,v 1.42 2006/01/25 23:21:37 djm Exp $
2.\" 2.\"
3.\" Copyright (c) 1996 David Sacerdote 3.\" Copyright (c) 1996 David Sacerdote
4.\" All rights reserved. 4.\" All rights reserved.
@@ -36,6 +36,7 @@
36.Bk -words 36.Bk -words
37.Op Fl 46DdhklnrStUuvz 37.Op Fl 46DdhklnrStUuvz
38.Op Fl i Ar interval 38.Op Fl i Ar interval
39.Op Fl P Ar proxy_username
39.Op Fl p Ar source_port 40.Op Fl p Ar source_port
40.Op Fl s Ar source_ip_address 41.Op Fl s Ar source_ip_address
41.Op Fl T Ar ToS 42.Op Fl T Ar ToS
@@ -128,6 +129,10 @@ option are ignored.
128.It Fl n 129.It Fl n
129Do not do any DNS or service lookups on any specified addresses, 130Do not do any DNS or service lookups on any specified addresses,
130hostnames or ports. 131hostnames or ports.
132.It Fl P Ar proxy_username
133Specifies a username to present to a proxy server that requires authentication.
134If no username is specified then authentication will not be attempted.
135Proxy authentication is only supported for HTTP CONNECT proxies at present.
131.It Fl p Ar source_port 136.It Fl p Ar source_port
132Specifies the source port 137Specifies the source port
133.Nm 138.Nm
@@ -386,6 +391,12 @@ directive in
386for more information. 391for more information.
387.Pp 392.Pp
388.Dl $ nc -x10.2.3.4:8080 -Xconnect host.example.com 42 393.Dl $ nc -x10.2.3.4:8080 -Xconnect host.example.com 42
394.Pp
395The same example again, this time enabling proxy authentication with username
396.Dq ruser
397if the proxy requires it:
398.Pp
399.Dl $ nc -x10.2.3.4:8080 -Xconnect -Pruser host.example.com 42
389.Sh SEE ALSO 400.Sh SEE ALSO
390.Xr cat 1 , 401.Xr cat 1 ,
391.Xr ssh 1 402.Xr ssh 1
diff --git a/src/usr.bin/nc/netcat.c b/src/usr.bin/nc/netcat.c
index a10a8954c5..cec87ff731 100644
--- a/src/usr.bin/nc/netcat.c
+++ b/src/usr.bin/nc/netcat.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: netcat.c,v 1.85 2006/01/20 00:01:20 millert Exp $ */ 1/* $OpenBSD: netcat.c,v 1.86 2006/01/25 23:21:37 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001 Eric Jackson <ericj@monkey.org> 3 * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
4 * 4 *
@@ -70,6 +70,7 @@ int jflag; /* use jumbo frames if we can */
70int kflag; /* More than one connect */ 70int kflag; /* More than one connect */
71int lflag; /* Bind to local port */ 71int lflag; /* Bind to local port */
72int nflag; /* Don't do name look up */ 72int nflag; /* Don't do name look up */
73char *Pflag; /* Proxy username */
73char *pflag; /* Localport flag */ 74char *pflag; /* Localport flag */
74int rflag; /* Random ports flag */ 75int rflag; /* Random ports flag */
75char *sflag; /* Source Address */ 76char *sflag; /* Source Address */
@@ -92,8 +93,8 @@ void help(void);
92int local_listen(char *, char *, struct addrinfo); 93int local_listen(char *, char *, struct addrinfo);
93void readwrite(int); 94void readwrite(int);
94int remote_connect(const char *, const char *, struct addrinfo); 95int remote_connect(const char *, const char *, struct addrinfo);
95int socks_connect(const char *, const char *, struct addrinfo, const char *, const char *, 96int socks_connect(const char *, const char *, struct addrinfo,
96 struct addrinfo, int); 97 const char *, const char *, struct addrinfo, int, const char *);
97int udptest(int); 98int udptest(int);
98int unix_connect(char *); 99int unix_connect(char *);
99int unix_listen(char *); 100int unix_listen(char *);
@@ -123,7 +124,7 @@ main(int argc, char *argv[])
123 sv = NULL; 124 sv = NULL;
124 125
125 while ((ch = getopt(argc, argv, 126 while ((ch = getopt(argc, argv,
126 "46Ddhi:jklnp:rSs:tT:Uuvw:X:x:z")) != -1) { 127 "46Ddhi:jklnP:p:rSs:tT:Uuvw:X:x:z")) != -1) {
127 switch (ch) { 128 switch (ch) {
128 case '4': 129 case '4':
129 family = AF_INET; 130 family = AF_INET;
@@ -167,6 +168,9 @@ main(int argc, char *argv[])
167 case 'n': 168 case 'n':
168 nflag = 1; 169 nflag = 1;
169 break; 170 break;
171 case 'P':
172 Pflag = optarg;
173 break;
170 case 'p': 174 case 'p':
171 pflag = optarg; 175 pflag = optarg;
172 break; 176 break;
@@ -354,7 +358,8 @@ main(int argc, char *argv[])
354 358
355 if (xflag) 359 if (xflag)
356 s = socks_connect(host, portlist[i], hints, 360 s = socks_connect(host, portlist[i], hints,
357 proxyhost, proxyport, proxyhints, socksv); 361 proxyhost, proxyport, proxyhints, socksv,
362 Pflag);
358 else 363 else
359 s = remote_connect(host, portlist[i], hints); 364 s = remote_connect(host, portlist[i], hints);
360 365
@@ -818,6 +823,7 @@ help(void)
818 \t-k Keep inbound sockets open for multiple connects\n\ 823 \t-k Keep inbound sockets open for multiple connects\n\
819 \t-l Listen mode, for inbound connects\n\ 824 \t-l Listen mode, for inbound connects\n\
820 \t-n Suppress name/port resolutions\n\ 825 \t-n Suppress name/port resolutions\n\
826 \t-P proxyuser\tUsername for proxy authentication\n\
821 \t-p port\t Specify local port for remote connects\n\ 827 \t-p port\t Specify local port for remote connects\n\
822 \t-r Randomize remote ports\n\ 828 \t-r Randomize remote ports\n\
823 \t-S Enable the TCP MD5 signature option\n\ 829 \t-S Enable the TCP MD5 signature option\n\
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