Download
vkoskiv
/MacNTP
/tcp.c
(View History)
vkoskiv Add copyright headers | Latest amendment: 12 on 2023-09-07 |
1 | /* |
2 | * Copyright (c) 2020 joshua stein <jcs@jcs.org> |
3 | * |
4 | * Permission to use, copy, modify, and distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above |
6 | * copyright notice and this permission notice appear in all copies. |
7 | * |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ |
16 | |
17 | #include <string.h> |
18 | #include "tcp.h" |
19 | |
20 | #define RCV_BUFFER_SIZE 1024 |
21 | #define TCP_BUFFER_SIZE 8192 |
22 | #define OPEN_TIMEOUT 60 |
23 | |
24 | /* define to enable SOCKS5 code */ |
25 | #undef SOCKS |
26 | |
27 | short gIPPDriverRefNum; |
28 | |
29 | unsigned long resolved_ip; |
30 | |
31 | // Invent our own memset, to avoid need to pull in all of ANSI-A4 |
32 | void mntp_memset(void *ptr, int c, long n) { |
33 | size_t i; |
34 | if (!ptr) return; |
35 | for (i = 0; i < n; ++i) { |
36 | // This feels weird |
37 | ((char *)ptr)[i] = (char)c; |
38 | } |
39 | } |
40 | |
41 | OSErr |
42 | _TCPInit(void) |
43 | { |
44 | ParamBlockRec pb; |
45 | OSErr osErr; |
46 | |
47 | mntp_memset(&pb, 0, sizeof(pb)); |
48 | |
49 | gIPPDriverRefNum = -1; |
50 | |
51 | pb.ioParam.ioCompletion = 0; |
52 | pb.ioParam.ioNamePtr = "\p.IPP"; |
53 | pb.ioParam.ioPermssn = fsCurPerm; |
54 | |
55 | osErr = PBOpen(&pb, false); |
56 | if (noErr == osErr) |
57 | gIPPDriverRefNum = pb.ioParam.ioRefNum; |
58 | |
59 | return osErr; |
60 | } |
61 | |
62 | OSErr |
63 | _TCPGetOurIP(ip_addr *ip, long *netMask) |
64 | { |
65 | OSErr osErr; |
66 | GetAddrParamBlock pb; |
67 | |
68 | mntp_memset(&pb, 0, sizeof(pb)); |
69 | |
70 | pb.csCode = ipctlGetAddr; |
71 | pb.ioCRefNum = gIPPDriverRefNum; |
72 | pb.ioResult = 1; |
73 | |
74 | osErr = PBControl((ParmBlkPtr)&pb, true); |
75 | while (pb.ioResult > 0) |
76 | ; |
77 | |
78 | if (pb.ioResult != noErr) |
79 | return pb.ioResult; |
80 | |
81 | if (ip != NULL) |
82 | *ip = pb.ourAddress; |
83 | if (netMask != NULL) |
84 | *netMask = pb.ourNetMask; |
85 | |
86 | return osErr; |
87 | } |
88 | |
89 | OSErr |
90 | _TCPCreate(TCPiopb *pb, StreamPtr *stream, Ptr rcvBufPtr, long rcvBufLen, |
91 | TCPNotifyProc aNotifyProc, Ptr userDataPtr, |
92 | TCPIOCompletionProc ioCompletion, Boolean async) |
93 | { |
94 | OSErr osErr; |
95 | |
96 | mntp_memset(pb, 0, sizeof(*pb)); |
97 | |
98 | pb->csCode = TCPCreate; |
99 | pb->ioCompletion = ioCompletion; |
100 | pb->ioCRefNum = gIPPDriverRefNum; |
101 | pb->ioResult = 1; |
102 | |
103 | pb->csParam.create.rcvBuff = rcvBufPtr; |
104 | pb->csParam.create.rcvBuffLen = rcvBufLen; |
105 | pb->csParam.create.notifyProc = aNotifyProc; |
106 | pb->csParam.create.userDataPtr = userDataPtr; |
107 | |
108 | osErr = PBControl((ParmBlkPtr)pb, async); |
109 | if (!async && (noErr == osErr)) { |
110 | *stream = pb->tcpStream; |
111 | } |
112 | |
113 | return osErr; |
114 | } |
115 | |
116 | /* listen for an incoming connection */ |
117 | OSErr |
118 | _TCPPassiveOpen(TCPiopb *pb, StreamPtr stream, ip_addr *remoteIP, |
119 | tcp_port *remotePort, ip_addr *localIP, tcp_port *localPort, |
120 | Ptr userData, TCPIOCompletionProc ioCompletion, Boolean async) |
121 | { |
122 | OSErr osErr; |
123 | short index; |
124 | |
125 | mntp_memset(pb, 0, sizeof(*pb)); |
126 | |
127 | pb->csCode = TCPPassiveOpen; |
128 | pb->ioCompletion = ioCompletion; |
129 | pb->ioCRefNum = gIPPDriverRefNum; |
130 | pb->tcpStream = stream; |
131 | pb->ioResult = 1; |
132 | |
133 | pb->csParam.open.ulpTimeoutAction = 1; /* abort half-open connection */ |
134 | pb->csParam.open.ulpTimeoutValue = 5; /* after 5 seconds */ |
135 | pb->csParam.open.validityFlags = 0xC0; |
136 | pb->csParam.open.commandTimeoutValue = 0; |
137 | pb->csParam.open.remoteHost = 0; |
138 | pb->csParam.open.remotePort = 0; |
139 | pb->csParam.open.localHost = 0; |
140 | pb->csParam.open.localPort = *localPort; |
141 | pb->csParam.open.tosFlags = 0x1; /* low delay */ |
142 | pb->csParam.open.precedence = 0; |
143 | pb->csParam.open.dontFrag = 0; |
144 | pb->csParam.open.timeToLive = 0; |
145 | pb->csParam.open.security = 0; |
146 | pb->csParam.open.optionCnt = 0; |
147 | pb->csParam.open.userDataPtr = userData; |
148 | |
149 | osErr = PBControl((ParmBlkPtr) pb, async); |
150 | if (!async && (osErr == noErr)) { |
151 | if (remoteIP) |
152 | *remoteIP = pb->csParam.open.remoteHost; |
153 | if (remotePort) |
154 | *remotePort = pb->csParam.open.remotePort; |
155 | if (localIP) |
156 | *localIP = pb->csParam.open.localHost; |
157 | *localPort = pb->csParam.open.localPort; |
158 | } |
159 | |
160 | return osErr; |
161 | } |
162 | |
163 | /* make an outgoing connection */ |
164 | OSErr |
165 | _TCPActiveOpen(TCPiopb *pb, StreamPtr stream, ip_addr remoteIP, |
166 | tcp_port remotePort, ip_addr *localIP, tcp_port *localPort, |
167 | Ptr userData, TCPIOCompletionProc ioCompletion, Boolean async) |
168 | { |
169 | OSErr osErr; |
170 | short index; |
171 | |
172 | mntp_memset(pb, 0, sizeof(*pb)); |
173 | |
174 | pb->csCode = TCPActiveOpen; |
175 | pb->ioCompletion = ioCompletion; |
176 | pb->ioCRefNum = gIPPDriverRefNum; |
177 | pb->tcpStream = stream; |
178 | pb->ioResult = 1; |
179 | |
180 | pb->csParam.open.ulpTimeoutValue = 30; |
181 | pb->csParam.open.ulpTimeoutAction = 1; |
182 | pb->csParam.open.validityFlags = 0xC0; |
183 | #if 0 |
184 | /* not available with this csCode */ |
185 | pb->csParam.open.commandTimeoutValue = 30; |
186 | #endif |
187 | pb->csParam.open.remoteHost = remoteIP; |
188 | pb->csParam.open.remotePort = remotePort; |
189 | pb->csParam.open.localHost = 0; |
190 | pb->csParam.open.localPort = *localPort; |
191 | pb->csParam.open.tosFlags = 0; |
192 | pb->csParam.open.precedence = 0; |
193 | pb->csParam.open.dontFrag = 0; |
194 | pb->csParam.open.timeToLive = 0; |
195 | pb->csParam.open.security = 0; |
196 | pb->csParam.open.optionCnt = 0; |
197 | for (index = 0; index < sizeof(pb->csParam.open.options); ++index) |
198 | pb->csParam.open.options[index] = 0; |
199 | pb->csParam.open.userDataPtr = userData; |
200 | |
201 | osErr = PBControl((ParmBlkPtr) pb, async); |
202 | if (!async && (noErr == osErr)) { |
203 | *localIP = pb->csParam.open.localHost; |
204 | *localPort = pb->csParam.open.localPort; |
205 | } |
206 | |
207 | return osErr; |
208 | } |
209 | |
210 | OSErr |
211 | _TCPSend(TCPiopb *pb, StreamPtr stream, wdsEntry *wdsPtr, Ptr userData, |
212 | TCPIOCompletionProc ioCompletion, Boolean async) |
213 | { |
214 | mntp_memset(pb, 0, sizeof(*pb)); |
215 | |
216 | pb->csCode = TCPSend; |
217 | pb->ioCompletion = ioCompletion; |
218 | pb->ioCRefNum = gIPPDriverRefNum; |
219 | pb->tcpStream = stream; |
220 | pb->ioResult = 1; |
221 | |
222 | pb->csParam.send.ulpTimeoutValue = 30; |
223 | pb->csParam.send.ulpTimeoutAction = 1; |
224 | pb->csParam.send.validityFlags = 0xC0; |
225 | pb->csParam.send.pushFlag = 1; /* XXX */ |
226 | pb->csParam.send.urgentFlag = 0; |
227 | pb->csParam.send.wdsPtr = (Ptr)wdsPtr; |
228 | pb->csParam.send.sendFree = 0; |
229 | pb->csParam.send.sendLength = 0; |
230 | pb->csParam.send.userDataPtr = userData; |
231 | |
232 | return PBControl((ParmBlkPtr)pb, async); |
233 | } |
234 | |
235 | OSErr |
236 | _TCPNoCopyRcv(TCPiopb *pb, StreamPtr stream, Ptr rdsPtr, |
237 | unsigned short rdsLength, Ptr userData, TCPIOCompletionProc ioCompletion, |
238 | Boolean async) |
239 | { |
240 | mntp_memset(pb, 0, sizeof(*pb)); |
241 | |
242 | pb->csCode = TCPNoCopyRcv; |
243 | pb->ioCompletion = ioCompletion; |
244 | pb->ioCRefNum = gIPPDriverRefNum; |
245 | pb->tcpStream = stream; |
246 | pb->ioResult = 1; |
247 | |
248 | pb->csParam.receive.commandTimeoutValue = 30; |
249 | pb->csParam.receive.urgentFlag = 0; |
250 | pb->csParam.receive.markFlag = 0; |
251 | pb->csParam.receive.rdsPtr = rdsPtr; |
252 | pb->csParam.receive.rdsLength = rdsLength; |
253 | pb->csParam.receive.userDataPtr = userData; |
254 | |
255 | return PBControl((ParmBlkPtr)pb, async); |
256 | } |
257 | |
258 | OSErr |
259 | _TCPRcv(TCPiopb *pb, StreamPtr stream, Ptr rcvBufPtr, |
260 | unsigned short *rcvBufLen, Ptr userData, TCPIOCompletionProc ioCompletion, |
261 | Boolean async) |
262 | { |
263 | OSErr osErr; |
264 | |
265 | mntp_memset(pb, 0, sizeof(*pb)); |
266 | |
267 | pb->csCode = TCPRcv; |
268 | pb->ioCompletion = ioCompletion; |
269 | pb->ioCRefNum = gIPPDriverRefNum; |
270 | pb->tcpStream = stream; |
271 | pb->ioResult = 1; |
272 | |
273 | pb->csParam.receive.commandTimeoutValue = 30; |
274 | pb->csParam.receive.urgentFlag = 0; |
275 | pb->csParam.receive.markFlag = 0; |
276 | pb->csParam.receive.rcvBuff = rcvBufPtr; |
277 | pb->csParam.receive.rcvBuffLen = *rcvBufLen; |
278 | pb->csParam.receive.userDataPtr = userData; |
279 | |
280 | osErr = PBControl((ParmBlkPtr)pb, async); |
281 | if (!async) |
282 | *rcvBufLen = pb->csParam.receive.rcvBuffLen; |
283 | |
284 | return osErr; |
285 | } |
286 | |
287 | OSErr |
288 | _TCPBfrReturn(TCPiopb *pb, StreamPtr stream, Ptr rdsPtr, Ptr userData, |
289 | TCPIOCompletionProc ioCompletion, Boolean async) |
290 | { |
291 | mntp_memset(pb, 0, sizeof(*pb)); |
292 | |
293 | pb->csCode = TCPRcvBfrReturn; |
294 | pb->ioCompletion = ioCompletion; |
295 | pb->ioCRefNum = gIPPDriverRefNum; |
296 | pb->tcpStream = stream; |
297 | pb->ioResult = 1; |
298 | |
299 | pb->csParam.receive.rdsPtr = rdsPtr; |
300 | pb->csParam.receive.userDataPtr = userData; |
301 | |
302 | return PBControl((ParmBlkPtr)pb, async); |
303 | } |
304 | |
305 | OSErr |
306 | _TCPClose(TCPiopb *pb, StreamPtr stream, Ptr userData, |
307 | TCPIOCompletionProc ioCompletion, Boolean async) |
308 | { |
309 | mntp_memset(pb, 0, sizeof(*pb)); |
310 | |
311 | pb->csCode = TCPClose; |
312 | pb->ioCompletion = ioCompletion; |
313 | pb->ioCRefNum = gIPPDriverRefNum; |
314 | pb->tcpStream = stream; |
315 | pb->ioResult = 1; |
316 | |
317 | pb->csParam.close.ulpTimeoutValue = 30; |
318 | pb->csParam.close.ulpTimeoutAction = 1; |
319 | pb->csParam.close.validityFlags = 0xC0; |
320 | pb->csParam.close.userDataPtr = userData; |
321 | |
322 | return PBControl((ParmBlkPtr)pb, async); |
323 | } |
324 | |
325 | OSErr |
326 | _TCPAbort(TCPiopb *pb, StreamPtr stream, Ptr userData, |
327 | TCPIOCompletionProc ioCompletion, Boolean async) |
328 | { |
329 | mntp_memset(pb, 0, sizeof(*pb)); |
330 | |
331 | pb->csCode = TCPAbort; |
332 | pb->ioCompletion = ioCompletion; |
333 | pb->ioCRefNum = gIPPDriverRefNum; |
334 | pb->tcpStream = stream; |
335 | pb->ioResult = 1; |
336 | |
337 | pb->csParam.abort.userDataPtr = userData; |
338 | |
339 | return PBControl((ParmBlkPtr)pb, async); |
340 | } |
341 | |
342 | OSErr |
343 | _TCPStatus(TCPiopb *pb, StreamPtr stream, struct TCPStatusPB *status, |
344 | Ptr userData, TCPIOCompletionProc ioCompletion, Boolean async) |
345 | { |
346 | OSErr osErr; |
347 | |
348 | mntp_memset(pb, 0, sizeof(*pb)); |
349 | |
350 | pb->csCode = TCPStatus; |
351 | pb->ioCompletion = ioCompletion; |
352 | pb->ioCRefNum = gIPPDriverRefNum; |
353 | pb->tcpStream = stream; |
354 | pb->csParam.status.userDataPtr = userData; |
355 | pb->ioResult = 1; |
356 | |
357 | osErr = PBControl((ParmBlkPtr)pb, async); |
358 | if (!async && (noErr == osErr)) { |
359 | *status = pb->csParam.status; |
360 | } |
361 | |
362 | return osErr; |
363 | } |
364 | |
365 | OSErr |
366 | _TCPRelease(TCPiopb *pb, StreamPtr stream, Ptr userData, |
367 | TCPIOCompletionProc ioCompletion, Boolean async) |
368 | { |
369 | OSErr osErr; |
370 | |
371 | mntp_memset(pb, 0, sizeof(*pb)); |
372 | |
373 | pb->csCode = TCPRelease; |
374 | pb->ioCompletion = ioCompletion; |
375 | pb->ioCRefNum = gIPPDriverRefNum; |
376 | pb->tcpStream = stream; |
377 | pb->ioResult = 1; |
378 | |
379 | pb->csParam.status.userDataPtr = userData; |
380 | |
381 | osErr = PBControl((ParmBlkPtr)pb, async); |
382 | |
383 | return osErr; |
384 | } |
385 | |
386 | OSErr |
387 | _UDPMaxMTUSize(UDPiopb *pb, short *mtu) |
388 | { |
389 | OSErr osErr; |
390 | |
391 | mntp_memset(pb, 0, sizeof(*pb)); |
392 | |
393 | pb->csCode = UDPMaxMTUSize; |
394 | pb->ioCRefNum = gIPPDriverRefNum; |
395 | pb->ioResult = 1; |
396 | |
397 | pb->csParam.mtu.remoteHost = (ip_addr)0; |
398 | |
399 | osErr = PBControl((ParmBlkPtr)pb, false); |
400 | |
401 | if (osErr == noErr) |
402 | *mtu = pb->csParam.mtu.mtuSize; |
403 | |
404 | return osErr; |
405 | } |
406 | |
407 | OSErr |
408 | _UDPCreate(UDPiopb *pb, StreamPtr *stream, Ptr rcvBufPtr, long rcvBufLen, |
409 | UDPNotifyProc aNotifyProc, Ptr userDataPtr, |
410 | UDPIOCompletionProc ioCompletion, Boolean async) |
411 | { |
412 | OSErr osErr; |
413 | |
414 | mntp_memset(pb, 0, sizeof(*pb)); |
415 | |
416 | pb->csCode = UDPCreate; |
417 | pb->ioCompletion = ioCompletion; |
418 | pb->ioCRefNum = gIPPDriverRefNum; |
419 | pb->ioResult = 1; |
420 | |
421 | pb->csParam.create.rcvBuff = rcvBufPtr; |
422 | pb->csParam.create.rcvBuffLen = rcvBufLen; |
423 | pb->csParam.create.notifyProc = aNotifyProc; |
424 | pb->csParam.create.userDataPtr = userDataPtr; |
425 | |
426 | osErr = PBControl((ParmBlkPtr)pb, async); |
427 | if (!async && (noErr == osErr)) { |
428 | *stream = pb->udpStream; |
429 | } |
430 | |
431 | return osErr; |
432 | } |
433 | |
434 | OSErr |
435 | _UDPSend(UDPiopb *pb, StreamPtr stream, wdsEntry *wdsPtr, ip_addr remoteIP, |
436 | udp_port remotePort, Ptr userData, UDPIOCompletionProc ioCompletion, |
437 | Boolean async) |
438 | { |
439 | mntp_memset(pb, 0, sizeof(*pb)); |
440 | |
441 | pb->csCode = UDPWrite; |
442 | pb->ioCompletion = ioCompletion; |
443 | pb->ioCRefNum = gIPPDriverRefNum; |
444 | pb->udpStream = stream; |
445 | pb->ioResult = 1; |
446 | |
447 | pb->csParam.send.remoteHost = remoteIP; |
448 | pb->csParam.send.remotePort = remotePort; |
449 | pb->csParam.send.wdsPtr = (Ptr)wdsPtr; |
450 | pb->csParam.send.checkSum = 0; |
451 | pb->csParam.send.sendLength = 0; |
452 | pb->csParam.send.userDataPtr = userData; |
453 | |
454 | return PBControl((ParmBlkPtr)pb, async); |
455 | } |
456 | |
457 | OSErr _UDPRcv(UDPiopb *pb, StreamPtr stream, Ptr rcvBufPtr, |
458 | unsigned short *rcvBufLen, ip_addr remoteIP, udp_port remotePort, Ptr userData, UDPIOCompletionProc ioCompletion, |
459 | Boolean async) |
460 | { |
461 | OSErr osErr; |
462 | |
463 | mntp_memset(pb, 0, sizeof(*pb)); |
464 | |
465 | pb->csCode = UDPRead; |
466 | pb->ioCompletion = ioCompletion; |
467 | pb->ioCRefNum = gIPPDriverRefNum; |
468 | pb->udpStream = stream; |
469 | pb->ioResult = 1; |
470 | |
471 | pb->csParam.receive.remoteHost = remoteIP; |
472 | pb->csParam.receive.remotePort = remotePort; |
473 | pb->csParam.receive.timeOut = 5; |
474 | pb->csParam.receive.rcvBuff = rcvBufPtr; |
475 | pb->csParam.receive.rcvBuffLen = *rcvBufLen; |
476 | pb->csParam.receive.userDataPtr = userData; |
477 | |
478 | osErr = PBControl((ParmBlkPtr)pb, async); |
479 | if (!async) |
480 | *rcvBufLen = pb->csParam.receive.rcvBuffLen; |
481 | |
482 | return osErr; |
483 | } |
484 | |
485 | OSErr |
486 | _UDPRelease(UDPiopb *pb, StreamPtr stream, Ptr userData, |
487 | UDPIOCompletionProc ioCompletion, Boolean async) |
488 | { |
489 | OSErr osErr; |
490 | |
491 | mntp_memset(pb, 0, sizeof(*pb)); |
492 | |
493 | pb->csCode = UDPRelease; |
494 | pb->ioCompletion = ioCompletion; |
495 | pb->ioCRefNum = gIPPDriverRefNum; |
496 | pb->udpStream = stream; |
497 | pb->ioResult = 1; |
498 | |
499 | //pb->csParam.status.userDataPtr = userData; |
500 | |
501 | osErr = PBControl((ParmBlkPtr)pb, async); |
502 | |
503 | return osErr; |
504 | } |
505 | |
506 | |
507 | /* convenience functions */ |
508 | |
509 | unsigned long |
510 | ip2long(char *ip) |
511 | { |
512 | unsigned long address = 0; |
513 | short dotcount = 0, i; |
514 | unsigned short b = 0; |
515 | |
516 | for (i = 0; ip[i] != 0; i++) { |
517 | if (ip[i] == '.') { |
518 | if (++dotcount > 3) |
519 | return (0); |
520 | address <<= 8; |
521 | address |= b; |
522 | b = 0; |
523 | } else if (ip[i] >= '0' && ip[i] <= '9') { |
524 | b *= 10; |
525 | b += (ip[i] - '0'); |
526 | if (b > 255) |
527 | return (0); |
528 | } else |
529 | return (0); |
530 | } |
531 | |
532 | if (dotcount != 3) |
533 | return (0); |
534 | address <<= 8; |
535 | address |= b; |
536 | return address; |
537 | } |
538 | |
539 | #ifdef SOCKS |
540 | #define SOCKS_VERSION_SOCKS5 0x5 |
541 | #define SOCKS_METHOD_AUTH_NONE 0x0 |
542 | #define SOCKS_REQUEST_CONNECT 0x1 |
543 | #define SOCKS_REQUEST_ATYP_DOMAINNAME 0x3 |
544 | #define SOCKS_REPLY_SUCCESS 0x0 |
545 | |
546 | OSErr |
547 | SOCKS5TCPActiveOpen(TCPiopb *pb, StreamPtr stream, ip_addr socks_ip, |
548 | tcp_port socks_port, char *remote_host, tcp_port remote_port, |
549 | ip_addr *local_ip, tcp_port *local_port, Ptr user_data, |
550 | TCPIOCompletionProc io_completion, Boolean async) |
551 | { |
552 | OSErr err; |
553 | TCPStatusPB status_pb; |
554 | wdsEntry wds[2]; |
555 | char data[255] = { 0 }; |
556 | unsigned short len, remote_host_len; |
557 | |
558 | remote_host_len = strlen(remote_host); |
559 | if (remote_host_len + 7 > sizeof(data)) |
560 | return -1; |
561 | |
562 | err = _TCPActiveOpen(pb, stream, socks_ip, socks_port, local_ip, |
563 | local_port, user_data, io_completion, async); |
564 | if (err != noErr) |
565 | return err; |
566 | |
567 | data[0] = SOCKS_VERSION_SOCKS5; |
568 | data[1] = 1; /* nmethods */ |
569 | data[2] = SOCKS_METHOD_AUTH_NONE; |
570 | |
571 | mntp_memset(&wds, 0, sizeof(wds)); |
572 | wds[0].ptr = (Ptr)&data; |
573 | wds[0].length = 3; |
574 | |
575 | err = _TCPSend(pb, stream, wds, nil, nil, false); |
576 | if (err) |
577 | goto fail; |
578 | |
579 | for (;;) { |
580 | err = _TCPStatus(pb, stream, &status_pb, nil, nil, false); |
581 | if (err != noErr) |
582 | goto fail; |
583 | |
584 | if (status_pb.amtUnreadData >= 2) |
585 | break; |
586 | } |
587 | |
588 | len = 2; |
589 | err = _TCPRcv(pb, stream, (Ptr)&data, &len, nil, nil, false); |
590 | if (err != noErr) |
591 | goto fail; |
592 | |
593 | if (data[0] != SOCKS_VERSION_SOCKS5 || data[1] != SOCKS_METHOD_AUTH_NONE) |
594 | goto fail; |
595 | |
596 | len = 0; |
597 | data[len++] = SOCKS_VERSION_SOCKS5; |
598 | data[len++] = SOCKS_REQUEST_CONNECT; |
599 | data[len++] = 0; /* reserved */ |
600 | data[len++] = SOCKS_REQUEST_ATYP_DOMAINNAME; |
601 | data[len++] = remote_host_len; |
602 | memcpy(data + len, remote_host, remote_host_len); |
603 | len += remote_host_len; |
604 | data[len++] = (remote_port >> 8); |
605 | data[len++] = (remote_port & 0xff); |
606 | |
607 | mntp_memset(&wds, 0, sizeof(wds)); |
608 | wds[0].ptr = (Ptr)&data; |
609 | wds[0].length = len; |
610 | |
611 | err = _TCPSend(pb, stream, wds, nil, nil, false); |
612 | if (err) |
613 | goto fail; |
614 | |
615 | for (;;) { |
616 | err = _TCPStatus(pb, stream, &status_pb, nil, nil, false); |
617 | if (err != noErr) |
618 | goto fail; |
619 | |
620 | if (status_pb.amtUnreadData >= 7) |
621 | break; |
622 | } |
623 | |
624 | len = status_pb.amtUnreadData; |
625 | if (len > sizeof(data)) |
626 | len = sizeof(data); |
627 | err = _TCPRcv(pb, stream, (Ptr)&data, &len, nil, nil, false); |
628 | if (err != noErr) |
629 | goto fail; |
630 | |
631 | if (data[0] != SOCKS_VERSION_SOCKS5 || data[1] != SOCKS_REPLY_SUCCESS) |
632 | goto fail; |
633 | |
634 | return noErr; |
635 | |
636 | fail: |
637 | _TCPClose(pb, stream, nil, nil, false); |
638 | return err; |
639 | } |
640 | #endif /* SOCKS */ |