summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/usr.bin/nc/socks.c158
1 files changed, 102 insertions, 56 deletions
diff --git a/src/usr.bin/nc/socks.c b/src/usr.bin/nc/socks.c
index ca67c6df59..7380b7999d 100644
--- a/src/usr.bin/nc/socks.c
+++ b/src/usr.bin/nc/socks.c
@@ -1,7 +1,8 @@
1/* $OpenBSD: socks.c,v 1.13 2005/05/20 11:06:58 djm Exp $ */ 1/* $OpenBSD: socks.c,v 1.14 2005/05/20 22:46:08 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1999 Niklas Hallqvist. All rights reserved. 4 * Copyright (c) 1999 Niklas Hallqvist. All rights reserved.
5 * Copyright (c) 2004, 2005 Damien Miller. All rights reserved.
5 * 6 *
6 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
@@ -46,42 +47,42 @@
46#define SOCKS_NOMETHOD 0xff 47#define SOCKS_NOMETHOD 0xff
47#define SOCKS_CONNECT 1 48#define SOCKS_CONNECT 1
48#define SOCKS_IPV4 1 49#define SOCKS_IPV4 1
50#define SOCKS_DOMAIN 3
51#define SOCKS_IPV6 4
49 52
50 53ssize_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t);
51int remote_connect(const char *, const char *, struct addrinfo); 54int remote_connect(const char *, const char *, struct addrinfo);
52int socks_connect(const char *host, const char *port, struct addrinfo hints, 55int socks_connect(const char *host, const char *port, struct addrinfo hints,
53 const char *proxyhost, const char *proxyport, struct addrinfo proxyhints, 56 const char *proxyhost, const char *proxyport, struct addrinfo proxyhints,
54 int socksv); 57 int socksv);
55 58
56static in_addr_t 59static int
57decode_addr(const char *s) 60decode_addrport(const char *h, const char *p, struct sockaddr *addr,
61 socklen_t addrlen, int v4only, int numeric)
58{ 62{
59 struct hostent *hp = gethostbyname(s); 63 int r;
60 struct in_addr retval; 64 struct addrinfo hints, *res;
61
62 if (hp)
63 return (*(in_addr_t *)hp->h_addr_list[0]);
64 if (inet_aton(s, &retval))
65 return (retval.s_addr);
66 errx(1, "cannot decode address \"%s\"", s);
67}
68 65
69static in_port_t 66 bzero(&hints, sizeof(hints));
70decode_port(const char *s) 67 hints.ai_family = v4only ? PF_INET : PF_UNSPEC;
71{ 68 hints.ai_flags = numeric ? AI_NUMERICHOST : 0;
72 struct servent *sp; 69 hints.ai_socktype = SOCK_STREAM;
73 in_port_t port; 70 r = getaddrinfo(h, p, &hints, &res);
74 char *p; 71 /* Don't fatal when attempting to convert a numeric address */
75 72 if (r != 0) {
76 port = strtol(s, &p, 10); 73 if (!numeric) {
77 if (s == p) { 74 errx(1, "getaddrinfo(\"%.64s\", \"%.64s\"): %s", h, p,
78 sp = getservbyname(s, "tcp"); 75 gai_strerror(r));
79 if (sp) 76 }
80 return (sp->s_port); 77 return (-1);
78 }
79 if (addrlen < res->ai_addrlen) {
80 freeaddrinfo(res);
81 errx(1, "internal error: addrlen < res->ai_addrlen");
81 } 82 }
82 if (*s != '\0' && *p == '\0') 83 memcpy(addr, res->ai_addr, res->ai_addrlen);
83 return (htons(port)); 84 freeaddrinfo(res);
84 errx (1, "cannot decode port \"%s\"", s); 85 return (0);
85} 86}
86 87
87static int 88static int
@@ -116,9 +117,12 @@ socks_connect(const char *host, const char *port,
116 int socksv) 117 int socksv)
117{ 118{
118 int proxyfd, r; 119 int proxyfd, r;
120 size_t hlen, wlen;
119 unsigned char buf[1024]; 121 unsigned char buf[1024];
120 ssize_t cnt; 122 ssize_t cnt;
121 in_addr_t serveraddr; 123 struct sockaddr_storage addr;
124 struct sockaddr_in *in4 = (struct sockaddr_in *)&addr;
125 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr;
122 in_port_t serverport; 126 in_port_t serverport;
123 127
124 if (proxyport == NULL) 128 if (proxyport == NULL)
@@ -129,12 +133,17 @@ socks_connect(const char *host, const char *port,
129 if (proxyfd < 0) 133 if (proxyfd < 0)
130 return (-1); 134 return (-1);
131 135
132 /* HTTP proxies should use hostnames. (XXX so can SOCKS5) */ 136 /* Abuse API to lookup port */
133 if (socksv != -1) 137 if (decode_addrport("0.0.0.0", port, (struct sockaddr *)&addr,
134 serveraddr = decode_addr(host); 138 sizeof(addr), 1, 1) == -1)
135 serverport = decode_port(port); 139 errx(1, "unknown port \"%.64s\"", port);
140 serverport = in4->sin_port;
136 141
137 if (socksv == 5) { 142 if (socksv == 5) {
143 if (decode_addrport(host, port, (struct sockaddr *)&addr,
144 sizeof(addr), 0, 1) == -1)
145 addr.ss_family = 0; /* used in switch below */
146
138 /* Version 5, one method: no authentication */ 147 /* Version 5, one method: no authentication */
139 buf[0] = SOCKS_V5; 148 buf[0] = SOCKS_V5;
140 buf[1] = 1; 149 buf[1] = 1;
@@ -149,23 +158,56 @@ socks_connect(const char *host, const char *port,
149 if (buf[1] == SOCKS_NOMETHOD) 158 if (buf[1] == SOCKS_NOMETHOD)
150 errx(1, "authentication method negotiation failed"); 159 errx(1, "authentication method negotiation failed");
151 160
152 /* Version 5, connect: IPv4 address */ 161 switch (addr.ss_family) {
153 buf[0] = SOCKS_V5; 162 case 0:
154 buf[1] = SOCKS_CONNECT; 163 /* Version 5, connect: domain name */
155 buf[2] = 0; 164
156 buf[3] = SOCKS_IPV4; 165 /* Max domain name length is 255 bytes */
157 memcpy(buf + 4, &serveraddr, sizeof serveraddr); 166 hlen = strlen(host);
158 memcpy(buf + 8, &serverport, sizeof serverport); 167 if (hlen > 255)
159 168 errx(1, "host name too long for SOCKS5");
160 /* XXX Handle short writes better */ 169 buf[0] = SOCKS_V5;
161 cnt = write(proxyfd, buf, 10); 170 buf[1] = SOCKS_CONNECT;
171 buf[2] = 0;
172 buf[3] = SOCKS_DOMAIN;
173 buf[4] = hlen;
174 memcpy(buf + 5, host, hlen);
175 memcpy(buf + 5 + hlen, &serverport, sizeof serverport);
176 wlen = 7 + hlen;
177 break;
178 case AF_INET:
179 /* Version 5, connect: IPv4 address */
180 buf[0] = SOCKS_V5;
181 buf[1] = SOCKS_CONNECT;
182 buf[2] = 0;
183 buf[3] = SOCKS_IPV4;
184 memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr);
185 memcpy(buf + 8, &in4->sin_port, sizeof in4->sin_port);
186 wlen = 10;
187 break;
188 case AF_INET6:
189 /* Version 5, connect: IPv6 address */
190 buf[0] = SOCKS_V5;
191 buf[1] = SOCKS_CONNECT;
192 buf[2] = 0;
193 buf[3] = SOCKS_IPV6;
194 memcpy(buf + 4, &in6->sin6_addr, sizeof in6->sin6_addr);
195 memcpy(buf + 20, &in6->sin6_port,
196 sizeof in6->sin6_port);
197 wlen = 22;
198 break;
199 default:
200 errx(1, "internal error: silly AF");
201 }
202
203 cnt = atomicio((ssize_t (*)(int, void *, size_t))write,
204 proxyfd, buf, wlen);
162 if (cnt == -1) 205 if (cnt == -1)
163 err(1, "write failed"); 206 err(1, "write failed");
164 if (cnt != 10) 207 if (cnt != wlen)
165 errx(1, "short write, %d (expected 10)", cnt); 208 errx(1, "short write, %d (expected %d)", cnt, wlen);
166 209
167 /* XXX Handle short reads better */ 210 cnt = atomicio(read, proxyfd, buf, 10);
168 cnt = read(proxyfd, buf, 10);
169 if (cnt == -1) 211 if (cnt == -1)
170 err(1, "read failed"); 212 err(1, "read failed");
171 if (cnt != 10) 213 if (cnt != 10)
@@ -173,21 +215,25 @@ socks_connect(const char *host, const char *port,
173 if (buf[1] != 0) 215 if (buf[1] != 0)
174 errx(1, "connection failed, SOCKS error %d", buf[1]); 216 errx(1, "connection failed, SOCKS error %d", buf[1]);
175 } else if (socksv == 4) { 217 } else if (socksv == 4) {
218 /* This will exit on lookup failure */
219 decode_addrport(host, port, (struct sockaddr *)&addr,
220 sizeof(addr), 1, 0);
221
176 /* Version 4 */ 222 /* Version 4 */
177 buf[0] = SOCKS_V4; 223 buf[0] = SOCKS_V4;
178 buf[1] = SOCKS_CONNECT; /* connect */ 224 buf[1] = SOCKS_CONNECT; /* connect */
179 memcpy(buf + 2, &serverport, sizeof serverport); 225 memcpy(buf + 2, &in4->sin_port, sizeof in4->sin_port);
180 memcpy(buf + 4, &serveraddr, sizeof serveraddr); 226 memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr);
181 buf[8] = 0; /* empty username */ 227 buf[8] = 0; /* empty username */
228 wlen = 9;
182 229
183 cnt = write(proxyfd, buf, 9); 230 cnt = write(proxyfd, buf, wlen);
184 if (cnt == -1) 231 if (cnt == -1)
185 err(1, "write failed"); 232 err(1, "write failed");
186 if (cnt != 9) 233 if (cnt != wlen)
187 errx(1, "short write, %d (expected 9)", cnt); 234 errx(1, "short write, %d (expected %d)", cnt, wlen);
188 235
189 /* XXX Handle short reads better */ 236 cnt = atomicio(read, proxyfd, buf, 8);
190 cnt = read(proxyfd, buf, 8);
191 if (cnt == -1) 237 if (cnt == -1)
192 err(1, "read failed"); 238 err(1, "read failed");
193 if (cnt != 8) 239 if (cnt != 8)
@@ -215,8 +261,8 @@ socks_connect(const char *host, const char *port,
215 errx(1, "hostname too long"); 261 errx(1, "hostname too long");
216 r = strlen(buf); 262 r = strlen(buf);
217 263
218 /* XXX atomicio */ 264 cnt = atomicio((ssize_t (*)(int, void *, size_t))write,
219 cnt = write(proxyfd, buf, r); 265 proxyfd, buf, r);
220 if (cnt == -1) 266 if (cnt == -1)
221 err(1, "write failed"); 267 err(1, "write failed");
222 if (cnt != r) 268 if (cnt != r)