diff options
author | djm <> | 2004-10-17 03:13:55 +0000 |
---|---|---|
committer | djm <> | 2004-10-17 03:13:55 +0000 |
commit | 91294475ad30114d23728b4a7599c81a0e1a99a3 (patch) | |
tree | 1f23c7ad55ad26e1dda318b65e9a34e4e26af6f1 /src/usr.bin/nc/socks.c | |
parent | 8a16cf0bfbdc91bb8136c9cedf795be3e0496e8c (diff) | |
download | openbsd-91294475ad30114d23728b4a7599c81a0e1a99a3.tar.gz openbsd-91294475ad30114d23728b4a7599c81a0e1a99a3.tar.bz2 openbsd-91294475ad30114d23728b4a7599c81a0e1a99a3.zip |
http proxy CONNECT support; ok beck@
Diffstat (limited to 'src/usr.bin/nc/socks.c')
-rw-r--r-- | src/usr.bin/nc/socks.c | 86 |
1 files changed, 76 insertions, 10 deletions
diff --git a/src/usr.bin/nc/socks.c b/src/usr.bin/nc/socks.c index a6b4fdd7e3..e7d35b601a 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.8 2003/07/07 21:36:23 deraadt Exp $ */ | 1 | /* $OpenBSD: socks.c,v 1.9 2004/10/17 03:13:55 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 1999 Niklas Hallqvist. All rights reserved. | 4 | * Copyright (c) 1999 Niklas Hallqvist. All rights reserved. |
@@ -30,6 +30,7 @@ | |||
30 | #include <arpa/inet.h> | 30 | #include <arpa/inet.h> |
31 | 31 | ||
32 | #include <err.h> | 32 | #include <err.h> |
33 | #include <errno.h> | ||
33 | #include <netdb.h> | 34 | #include <netdb.h> |
34 | #include <stdio.h> | 35 | #include <stdio.h> |
35 | #include <stdlib.h> | 36 | #include <stdlib.h> |
@@ -37,13 +38,15 @@ | |||
37 | #include <unistd.h> | 38 | #include <unistd.h> |
38 | 39 | ||
39 | #define SOCKS_PORT "1080" | 40 | #define SOCKS_PORT "1080" |
41 | #define HTTP_PROXY_PORT "3128" | ||
42 | #define HTTP_MAXHDRS 64 | ||
40 | #define SOCKS_V5 5 | 43 | #define SOCKS_V5 5 |
41 | #define SOCKS_V4 4 | 44 | #define SOCKS_V4 4 |
42 | #define SOCKS_NOAUTH 0 | 45 | #define SOCKS_NOAUTH 0 |
43 | #define SOCKS_NOMETHOD 0xff | 46 | #define SOCKS_NOMETHOD 0xff |
44 | #define SOCKS_CONNECT 1 | 47 | #define SOCKS_CONNECT 1 |
45 | #define SOCKS_IPV4 1 | 48 | #define SOCKS_IPV4 1 |
46 | #define SOCKS_MAXCMDSZ 10 | 49 | |
47 | 50 | ||
48 | int remote_connect(char *, char *, struct addrinfo); | 51 | int remote_connect(char *, char *, struct addrinfo); |
49 | int socks_connect(char *host, char *port, struct addrinfo hints, | 52 | int socks_connect(char *host, char *port, struct addrinfo hints, |
@@ -81,21 +84,46 @@ decode_port(const char *s) | |||
81 | errx (1, "cannot decode port \"%s\"", s); | 84 | errx (1, "cannot decode port \"%s\"", s); |
82 | } | 85 | } |
83 | 86 | ||
87 | static int | ||
88 | proxy_read_line(int fd, char *buf, int bufsz) | ||
89 | { | ||
90 | int r, off; | ||
91 | |||
92 | for(off = 0;;) { | ||
93 | if (off >= bufsz) | ||
94 | errx(1, "proxy read too long"); | ||
95 | if ((r = read(fd, buf + off, 1)) <= 0) { | ||
96 | if (r == -1 && errno == EINTR) | ||
97 | continue; | ||
98 | err(1, "proxy read"); | ||
99 | } | ||
100 | /* Skip CR */ | ||
101 | if (buf[off] == '\r') | ||
102 | continue; | ||
103 | if (buf[off] == '\n') { | ||
104 | buf[off] = '\0'; | ||
105 | break; | ||
106 | } | ||
107 | off++; | ||
108 | } | ||
109 | return (off); | ||
110 | } | ||
111 | |||
84 | int | 112 | int |
85 | socks_connect(char *host, char *port, struct addrinfo hints, | 113 | socks_connect(char *host, char *port, struct addrinfo hints, |
86 | char *proxyhost, char *proxyport, struct addrinfo proxyhints, | 114 | char *proxyhost, char *proxyport, struct addrinfo proxyhints, |
87 | int socksv) | 115 | int socksv) |
88 | { | 116 | { |
89 | int proxyfd; | 117 | int proxyfd, r; |
90 | unsigned char buf[SOCKS_MAXCMDSZ]; | 118 | unsigned char buf[1024]; |
91 | ssize_t cnt; | 119 | ssize_t cnt; |
92 | in_addr_t serveraddr; | 120 | in_addr_t serveraddr; |
93 | in_port_t serverport; | 121 | in_port_t serverport; |
94 | 122 | ||
95 | if (proxyport) | 123 | if (proxyport == NULL) |
96 | proxyfd = remote_connect(proxyhost, proxyport, proxyhints); | 124 | proxyport = (socksv == -1) ? HTTP_PROXY_PORT : SOCKS_PORT; |
97 | else | 125 | |
98 | proxyfd = remote_connect(proxyhost, SOCKS_PORT, proxyhints); | 126 | proxyfd = remote_connect(proxyhost, proxyport, proxyhints); |
99 | 127 | ||
100 | if (proxyfd < 0) | 128 | if (proxyfd < 0) |
101 | return -1; | 129 | return -1; |
@@ -141,7 +169,7 @@ socks_connect(char *host, char *port, struct addrinfo hints, | |||
141 | errx (1, "unexpected reply size %d (expected 10)", cnt); | 169 | errx (1, "unexpected reply size %d (expected 10)", cnt); |
142 | if (buf[1] != 0) | 170 | if (buf[1] != 0) |
143 | errx (1, "connection failed, SOCKS error %d", buf[1]); | 171 | errx (1, "connection failed, SOCKS error %d", buf[1]); |
144 | } else { | 172 | } else if (socksv == 4) { |
145 | /* Version 4 */ | 173 | /* Version 4 */ |
146 | buf[0] = SOCKS_V4; | 174 | buf[0] = SOCKS_V4; |
147 | buf[1] = SOCKS_CONNECT; /* connect */ | 175 | buf[1] = SOCKS_CONNECT; /* connect */ |
@@ -163,7 +191,45 @@ socks_connect(char *host, char *port, struct addrinfo hints, | |||
163 | errx (1, "unexpected reply size %d (expected 8)", cnt); | 191 | errx (1, "unexpected reply size %d (expected 8)", cnt); |
164 | if (buf[1] != 90) | 192 | if (buf[1] != 90) |
165 | errx (1, "connection failed, SOCKS error %d", buf[1]); | 193 | errx (1, "connection failed, SOCKS error %d", buf[1]); |
166 | } | 194 | } else if (socksv == -1) { |
195 | /* HTTP proxy CONNECT */ | ||
196 | |||
197 | /* Disallow bad chars in hostname */ | ||
198 | if (strcspn(host, "\r\n\t []:") != strlen(host)) | ||
199 | errx (1, "Invalid hostname"); | ||
200 | |||
201 | /* Try to be sane about numeric IPv6 addresses */ | ||
202 | if (strchr(host, ':') != NULL) { | ||
203 | r = snprintf(buf, sizeof(buf), | ||
204 | "CONNECT [%s]:%d HTTP/1.0\r\n\r\n", | ||
205 | host, ntohs(serverport)); | ||
206 | } else { | ||
207 | r = snprintf(buf, sizeof(buf), | ||
208 | "CONNECT %s:%d HTTP/1.0\r\n\r\n", | ||
209 | host, ntohs(serverport)); | ||
210 | } | ||
211 | if (r == -1 || r >= sizeof(buf)) | ||
212 | errx (1, "hostname too long"); | ||
213 | r = strlen(buf); | ||
214 | |||
215 | /* XXX atomicio */ | ||
216 | cnt = write (proxyfd, buf, r); | ||
217 | if (cnt == -1) | ||
218 | err (1, "write failed"); | ||
219 | if (cnt != r) | ||
220 | errx (1, "short write, %d (expected %d)", cnt, r); | ||
221 | |||
222 | /* Read reply */ | ||
223 | for (r = 0; r < HTTP_MAXHDRS; r++) { | ||
224 | proxy_read_line(proxyfd, buf, sizeof(buf)); | ||
225 | if (r == 0 && strncmp(buf, "HTTP/1.0 200 ", 12) != 0) | ||
226 | errx (1, "Proxy error: \"%s\"", buf); | ||
227 | /* Discard headers until we hit an empty line */ | ||
228 | if (*buf == '\0') | ||
229 | break; | ||
230 | } | ||
231 | } else | ||
232 | errx (1, "Unknown proxy protocol %d", socksv); | ||
167 | 233 | ||
168 | return proxyfd; | 234 | return proxyfd; |
169 | } | 235 | } |