AmendHub

Download

jcs

/

wikipedia

/

tcp.c

 

(View History)

jcs   tcp: Sync with upstream Latest amendment: 39 on 2023-08-28

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