1/* 2 * tcp.c - TCP module 3 * 4 * This file is part of zsh, the Z shell. 5 * 6 * Copyright (c) 1998-2001 Peter Stephenson 7 * All rights reserved. 8 * 9 * Permission is hereby granted, without written agreement and without 10 * license or royalty fees, to use, copy, modify, and distribute this 11 * software and to distribute modified versions of this software for any 12 * purpose, provided that the above copyright notice and the following 13 * two paragraphs appear in all copies of this software. 14 * 15 * In no event shall Peter Stephenson or the Zsh Development 16 * Group be liable to any party for direct, indirect, special, incidental, 17 * or consequential damages arising out of the use of this software and 18 * its documentation, even if Peter Stephenson, and the Zsh 19 * Development Group have been advised of the possibility of such damage. 20 * 21 * Peter Stephenson and the Zsh Development Group specifically 22 * disclaim any warranties, including, but not limited to, the implied 23 * warranties of merchantability and fitness for a particular purpose. The 24 * software provided hereunder is on an "as is" basis, and Peter Stephenson 25 * and the Zsh Development Group have no obligation to provide maintenance, 26 * support, updates, enhancements, or modifications. 27 * 28 */ 29 30/* 31 * We need to include the zsh headers later to avoid clashes with 32 * the definitions on some systems, however we need the configuration 33 * file to decide whether we can include netinet/in_systm.h, which 34 * doesn't exist on cygwin. 35 */ 36#include "tcp.h" 37#include "tcp.mdh" 38 39/* 40 * We use poll() in preference to select because some subset of manuals says 41 * that's the thing to do, plus it's a bit less fiddly. I don't actually 42 * have access to a system with poll but not select, however, though 43 * both bits of the code have been tested on a machine with both. 44 */ 45#ifdef HAVE_POLL_H 46# include <poll.h> 47#endif 48#if defined(HAVE_POLL) && !defined(POLLIN) && !defined(POLLNORM) 49# undef HAVE_POLL 50#endif 51 52#ifdef USE_LOCAL_H_ERRNO 53int h_errno; 54#endif 55 56/* We use the RFC 2553 interfaces. If the functions don't exist in the 57 * library, simulate them. */ 58 59#ifndef INET_ADDRSTRLEN 60# define INET_ADDRSTRLEN 16 61#endif 62 63#ifndef INET6_ADDRSTRLEN 64# define INET6_ADDRSTRLEN 46 65#endif 66 67/**/ 68#ifndef HAVE_INET_NTOP 69 70/**/ 71mod_export char const * 72zsh_inet_ntop(int af, void const *cp, char *buf, size_t len) 73{ 74 if (af != AF_INET) { 75 errno = EAFNOSUPPORT; 76 return NULL; 77 } 78 if (len < INET_ADDRSTRLEN) { 79 errno = ENOSPC; 80 return NULL; 81 } 82 strcpy(buf, inet_ntoa(*(struct in_addr *)cp)); 83 return buf; 84} 85 86/**/ 87#else /* !HAVE_INET_NTOP */ 88 89/**/ 90# define zsh_inet_ntop inet_ntop 91 92/**/ 93#endif /* !HAVE_INET_NTOP */ 94 95/**/ 96#ifndef HAVE_INET_ATON 97 98# ifndef INADDR_NONE 99# define INADDR_NONE 0xffffffffUL 100# endif 101 102/**/ 103mod_export int zsh_inet_aton(char const *src, struct in_addr *dst) 104{ 105 return (dst->s_addr = inet_addr(src)) != INADDR_NONE; 106} 107 108/**/ 109#else /* !HAVE_INET_ATON */ 110 111/**/ 112# define zsh_inet_aton inet_aton 113 114/**/ 115#endif /* !HAVE_INET_ATON */ 116 117/**/ 118#ifndef HAVE_INET_PTON 119 120/**/ 121mod_export int 122zsh_inet_pton(int af, char const *src, void *dst) 123{ 124 if (af != AF_INET) { 125 errno = EAFNOSUPPORT; 126 return -1; 127 } 128 return !!zsh_inet_aton(src, dst); 129} 130 131#else /* !HAVE_INET_PTON */ 132 133# define zsh_inet_pton inet_pton 134 135/**/ 136#endif /* !HAVE_INET_PTON */ 137 138/**/ 139#ifndef HAVE_GETIPNODEBYNAME 140 141/**/ 142# ifndef HAVE_GETHOSTBYNAME2 143 144/**/ 145mod_export struct hostent * 146zsh_gethostbyname2(char const *name, int af) 147{ 148 if (af != AF_INET) { 149 h_errno = NO_RECOVERY; 150 return NULL; 151 } 152 return gethostbyname(name); 153} 154 155/**/ 156#else /* !HAVE_GETHOSTBYNAME2 */ 157 158/**/ 159# define zsh_gethostbyname2 gethostbyname2 160 161/**/ 162# endif /* !HAVE_GETHOSTBYNAME2 */ 163 164/* note: this is not a complete implementation. If ignores the flags, 165 and does not provide the memory allocation of the standard interface. 166 Each returned structure will overwrite the previous one. */ 167 168/**/ 169mod_export struct hostent * 170zsh_getipnodebyname(char const *name, int af, UNUSED(int flags), int *errorp) 171{ 172 static struct hostent ahe; 173 static char nbuf[16]; 174 static char *addrlist[] = { nbuf, NULL }; 175# ifdef SUPPORT_IPV6 176 static char pbuf[INET6_ADDRSTRLEN]; 177# else 178 static char pbuf[INET_ADDRSTRLEN]; 179# endif 180 struct hostent *he; 181 if (zsh_inet_pton(af, name, nbuf) == 1) { 182 zsh_inet_ntop(af, nbuf, pbuf, sizeof(pbuf)); 183 ahe.h_name = pbuf; 184 ahe.h_aliases = addrlist+1; 185 ahe.h_addrtype = af; 186 ahe.h_length = (af == AF_INET) ? 4 : 16; 187 ahe.h_addr_list = addrlist; 188 return &ahe; 189 } 190 he = zsh_gethostbyname2(name, af); 191 if (!he) 192 *errorp = h_errno; 193 return he; 194} 195 196/**/ 197mod_export void 198freehostent(UNUSED(struct hostent *ptr)) 199{ 200} 201 202/**/ 203#else /* !HAVE_GETIPNODEBYNAME */ 204 205/**/ 206# define zsh_getipnodebyname getipnodebyname 207 208/**/ 209#endif /* !HAVE_GETIPNODEBYNAME */ 210 211LinkList ztcp_sessions; 212 213/* "allocate" a tcp_session */ 214static Tcp_session 215zts_alloc(int ztflags) 216{ 217 Tcp_session sess; 218 219 sess = (Tcp_session)zshcalloc(sizeof(struct tcp_session)); 220 if (!sess) return NULL; 221 sess->fd=-1; 222 sess->flags=ztflags; 223 224 zinsertlinknode(ztcp_sessions, lastnode(ztcp_sessions), (void *)sess); 225 226 return sess; 227} 228 229/**/ 230mod_export Tcp_session 231tcp_socket(int domain, int type, int protocol, int ztflags) 232{ 233 Tcp_session sess; 234 235 sess = zts_alloc(ztflags); 236 if (!sess) return NULL; 237 238 sess->fd = socket(domain, type, protocol); 239 return sess; 240} 241 242static int 243ztcp_free_session(Tcp_session sess) 244{ 245 zfree(sess, sizeof(struct tcp_session)); 246 247 return 0; 248} 249 250static int 251zts_delete(Tcp_session sess) 252{ 253 LinkNode node; 254 255 node = linknodebydatum(ztcp_sessions, (void *)sess); 256 257 if (!node) 258 { 259 return 1; 260 } 261 262 ztcp_free_session(getdata(node)); 263 remnode(ztcp_sessions, node); 264 265 return 0; 266} 267 268static Tcp_session 269zts_byfd(int fd) 270{ 271 LinkNode node; 272 273 for (node = firstnode(ztcp_sessions); node; incnode(node)) 274 if (((Tcp_session)getdata(node))->fd == fd) 275 return (Tcp_session)getdata(node); 276 277 return NULL; 278} 279 280static void 281tcp_cleanup(void) 282{ 283 LinkNode node, next; 284 285 for (node = firstnode(ztcp_sessions); node; node = next) { 286 next = node->next; 287 tcp_close((Tcp_session)getdata(node)); 288 } 289} 290 291/**/ 292mod_export int 293tcp_close(Tcp_session sess) 294{ 295 int err; 296 297 if (sess) 298 { 299 if (sess->fd != -1) 300 { 301 err = close(sess->fd); 302 if (err) 303 zwarn("connection close failed: %e", errno); 304 } 305 zts_delete(sess); 306 return 0; 307 } 308 309 return -1; 310} 311 312/**/ 313mod_export int 314tcp_connect(Tcp_session sess, char *addrp, struct hostent *zhost, int d_port) 315{ 316 int salen; 317#ifdef SUPPORT_IPV6 318 if (zhost->h_addrtype==AF_INET6) { 319 memcpy(&(sess->peer.in6.sin6_addr), addrp, zhost->h_length); 320 sess->peer.in6.sin6_port = d_port; 321 sess->peer.in6.sin6_flowinfo = 0; 322# ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 323 sess->peer.in6.sin6_scope_id = 0; 324# endif 325 sess->peer.in6.sin6_family = zhost->h_addrtype; 326 salen = sizeof(struct sockaddr_in6); 327 } else 328#endif /* SUPPORT_IPV6 */ 329 { 330 memcpy(&(sess->peer.in.sin_addr), addrp, zhost->h_length); 331 sess->peer.in.sin_port = d_port; 332 sess->peer.in.sin_family = zhost->h_addrtype; 333 salen = sizeof(struct sockaddr_in); 334 } 335 336 return connect(sess->fd, (struct sockaddr *)&(sess->peer), salen); 337} 338 339static int 340bin_ztcp(char *nam, char **args, Options ops, UNUSED(int func)) 341{ 342 int herrno, err=1, destport, force=0, verbose=0, test=0, targetfd=0; 343 ZSOCKLEN_T len; 344 char **addrp, *desthost, *localname, *remotename; 345 struct hostent *zthost = NULL, *ztpeer = NULL; 346 struct servent *srv; 347 Tcp_session sess = NULL; 348 349 if (OPT_ISSET(ops,'f')) 350 force = 1; 351 352 if (OPT_ISSET(ops,'v')) 353 verbose = 1; 354 355 if (OPT_ISSET(ops,'t')) 356 test = 1; 357 358 if (OPT_ISSET(ops,'d')) { 359 targetfd = atoi(OPT_ARG(ops,'d')); 360 if (!targetfd) { 361 zwarnnam(nam, "%s is an invalid argument to -d", OPT_ARG(ops,'d')); 362 return 1; 363 } 364 } 365 366 367 if (OPT_ISSET(ops,'c')) { 368 if (!args[0]) { 369 tcp_cleanup(); 370 } 371 else { 372 targetfd = atoi(args[0]); 373 sess = zts_byfd(targetfd); 374 if(!targetfd) { 375 zwarnnam(nam, "%s is an invalid argument to -c", args[0]); 376 return 1; 377 } 378 379 if (sess) 380 { 381 if ((sess->flags & ZTCP_ZFTP) && !force) 382 { 383 zwarnnam(nam, "use -f to force closure of a zftp control connection"); 384 return 1; 385 } 386 tcp_close(sess); 387 return 0; 388 } 389 else 390 { 391 zwarnnam(nam, "fd %s not found in tcp table", args[0]); 392 return 1; 393 } 394 } 395 } 396 else if (OPT_ISSET(ops,'l')) { 397 int lport = 0; 398 399 if (!args[0]) { 400 zwarnnam(nam, "-l requires an argument"); 401 return 1; 402 } 403 404 srv = getservbyname(args[0], "tcp"); 405 if (srv) 406 lport = srv->s_port; 407 else 408 lport = htons(atoi(args[0])); 409 if (!lport) { zwarnnam(nam, "bad service name or port number"); 410 return 1; 411 } 412 sess = tcp_socket(PF_INET, SOCK_STREAM, 0, ZTCP_LISTEN); 413 414 if (!sess) { 415 zwarnnam(nam, "unable to allocate a TCP session slot"); 416 return 1; 417 } 418#ifdef SO_OOBINLINE 419 len = 1; 420 setsockopt(sess->fd, SOL_SOCKET, SO_OOBINLINE, (char *)&len, sizeof(len)); 421#endif 422 if (!zsh_inet_aton("0.0.0.0", &(sess->sock.in.sin_addr))) 423 { 424 zwarnnam(nam, "bad address: %s", "0.0.0.0"); 425 return 1; 426 } 427 428 sess->sock.in.sin_family = AF_INET; 429 sess->sock.in.sin_port = lport; 430 431 432 if (bind(sess->fd, (struct sockaddr *)&sess->sock.in, sizeof(struct sockaddr_in))) 433 { 434 char buf[DIGBUFSIZE]; 435 convbase(buf, (zlong)ntohs(lport), 10); 436 zwarnnam(nam, "could not bind to port %s: %e", buf, errno); 437 tcp_close(sess); 438 return 1; 439 } 440 441 if (listen(sess->fd, 1)) 442 { 443 zwarnnam(nam, "could not listen on socket: %e", errno); 444 tcp_close(sess); 445 return 1; 446 } 447 448 if (targetfd) { 449 sess->fd = redup(sess->fd, targetfd); 450 } 451 else { 452 /* move the fd since no one will want to read from it */ 453 sess->fd = movefd(sess->fd); 454 } 455 456 if (sess->fd == -1) { 457 zwarnnam(nam, "cannot duplicate fd %d: %e", sess->fd, errno); 458 tcp_close(sess); 459 return 1; 460 } 461 462 setiparam("REPLY", sess->fd); 463 464 if (verbose) 465 printf("%d listener is on fd %d\n", ntohs(sess->sock.in.sin_port), sess->fd); 466 467 return 0; 468 469 } 470 else if (OPT_ISSET(ops,'a')) 471 { 472 int lfd, rfd; 473 474 if (!args[0]) { 475 zwarnnam(nam, "-a requires an argument"); 476 return 1; 477 } 478 479 lfd = atoi(args[0]); 480 481 if (!lfd) { 482 zwarnnam(nam, "invalid numerical argument"); 483 return 1; 484 } 485 486 sess = zts_byfd(lfd); 487 if (!sess) { 488 zwarnnam(nam, "fd %s is not registered as a tcp connection", args[0]); 489 return 1; 490 } 491 492 if (!(sess->flags & ZTCP_LISTEN)) 493 { 494 zwarnnam(nam, "tcp connection not a listener"); 495 return 1; 496 } 497 498 if (test) { 499#if defined(HAVE_POLL) || defined(HAVE_SELECT) 500# ifdef HAVE_POLL 501 struct pollfd pfd; 502 int ret; 503 504 pfd.fd = lfd; 505 pfd.events = POLLIN; 506 if ((ret = poll(&pfd, 1, 0)) == 0) return 1; 507 else if (ret == -1) 508 { 509 zwarnnam(nam, "poll error: %e", errno); 510 return 1; 511 } 512# else 513 fd_set rfds; 514 struct timeval tv; 515 int ret; 516 517 FD_ZERO(&rfds); 518 FD_SET(lfd, &rfds); 519 tv.tv_sec = 0; 520 tv.tv_usec = 0; 521 522 if ((ret = select(lfd+1, &rfds, NULL, NULL, &tv))) return 1; 523 else if (ret == -1) 524 { 525 zwarnnam(nam, "select error: %e", errno); 526 return 1; 527 } 528 529# endif 530 531#else 532 zwarnnam(nam, "not currently supported"); 533 return 1; 534#endif 535 } 536 sess = zts_alloc(ZTCP_INBOUND); 537 538 len = sizeof(sess->peer.in); 539 if ((rfd = accept(lfd, (struct sockaddr *)&sess->peer.in, &len)) == -1) 540 { 541 zwarnnam(nam, "could not accept connection: %e", errno); 542 tcp_close(sess); 543 return 1; 544 } 545 546 if (targetfd) { 547 sess->fd = redup(rfd, targetfd); 548 if (sess->fd < 0) { 549 zerrnam(nam, "could not duplicate socket fd to %d: %e", targetfd, errno); 550 return 1; 551 } 552 } 553 else { 554 sess->fd = rfd; 555 } 556 557 setiparam("REPLY", sess->fd); 558 559 if (verbose) 560 printf("%d is on fd %d\n", ntohs(sess->peer.in.sin_port), sess->fd); 561 } 562 else 563 { 564 if (!args[0]) { 565 LinkNode node; 566 for(node = firstnode(ztcp_sessions); node; incnode(node)) 567 { 568 sess = (Tcp_session)getdata(node); 569 570 if (sess->fd != -1) 571 { 572 zthost = gethostbyaddr((const void *)&(sess->sock.in.sin_addr), sizeof(sess->sock.in.sin_addr), AF_INET); 573 if (zthost) 574 localname = zthost->h_name; 575 else 576 localname = inet_ntoa(sess->sock.in.sin_addr); 577 ztpeer = gethostbyaddr((const void *)&(sess->peer.in.sin_addr), sizeof(sess->peer.in.sin_addr), AF_INET); 578 if (ztpeer) 579 remotename = ztpeer->h_name; 580 else 581 remotename = inet_ntoa(sess->peer.in.sin_addr); 582 if (OPT_ISSET(ops,'L')) { 583 int schar; 584 if (sess->flags & ZTCP_ZFTP) 585 schar = 'Z'; 586 else if (sess->flags & ZTCP_LISTEN) 587 schar = 'L'; 588 else if (sess->flags & ZTCP_INBOUND) 589 schar = 'I'; 590 else 591 schar = 'O'; 592 printf("%d %c %s %d %s %d\n", 593 sess->fd, schar, 594 localname, ntohs(sess->sock.in.sin_port), 595 remotename, ntohs(sess->peer.in.sin_port)); 596 } else { 597 printf("%s:%d %s %s:%d is on fd %d%s\n", 598 localname, ntohs(sess->sock.in.sin_port), 599 ((sess->flags & ZTCP_LISTEN) ? "-<" : 600 ((sess->flags & ZTCP_INBOUND) ? "<-" : "->")), 601 remotename, ntohs(sess->peer.in.sin_port), 602 sess->fd, 603 (sess->flags & ZTCP_ZFTP) ? " ZFTP" : ""); 604 } 605 } 606 } 607 return 0; 608 } 609 else if (!args[1]) { 610 destport = htons(23); 611 } 612 else { 613 614 srv = getservbyname(args[1],"tcp"); 615 if (srv) 616 destport = srv->s_port; 617 else 618 destport = htons(atoi(args[1])); 619 } 620 621 desthost = ztrdup(args[0]); 622 623 zthost = zsh_getipnodebyname(desthost, AF_INET, 0, &herrno); 624 if (!zthost || errflag) { 625 zwarnnam(nam, "host resolution failure: %s", desthost); 626 return 1; 627 } 628 629 sess = tcp_socket(PF_INET, SOCK_STREAM, 0, 0); 630 631 if (!sess) { 632 zwarnnam(nam, "unable to allocate a TCP session slot"); 633 return 1; 634 } 635 636#ifdef SO_OOBINLINE 637 len = 1; 638 setsockopt(sess->fd, SOL_SOCKET, SO_OOBINLINE, (char *)&len, sizeof(len)); 639#endif 640 641 if (sess->fd < 0) { 642 zwarnnam(nam, "socket creation failed: %e", errno); 643 zsfree(desthost); 644 zts_delete(sess); 645 return 1; 646 } 647 648 for (addrp = zthost->h_addr_list; err && *addrp; addrp++) { 649 if (zthost->h_length != 4) 650 zwarnnam(nam, "address length mismatch"); 651 do { 652 err = tcp_connect(sess, *addrp, zthost, destport); 653 } while (err && errno == EINTR && !errflag); 654 } 655 656 if (err) { 657 zwarnnam(nam, "connection failed: %e", errno); 658 tcp_close(sess); 659 zsfree(desthost); 660 return 1; 661 } 662 else 663 { 664 if (targetfd) { 665 sess->fd = redup(sess->fd, targetfd); 666 if (sess->fd < 0) { 667 zerrnam(nam, "could not duplicate socket fd to %d: %e", targetfd, errno); 668 return 1; 669 } 670 } 671 672 setiparam("REPLY", sess->fd); 673 674 if (verbose) 675 printf("%s:%d is now on fd %d\n", 676 desthost, destport, sess->fd); 677 } 678 679 zsfree(desthost); 680 } 681 682 return 0; 683} 684 685static struct builtin bintab[] = { 686 BUILTIN("ztcp", 0, bin_ztcp, 0, 3, 0, "acd:flLtv", NULL), 687}; 688 689static struct features module_features = { 690 bintab, sizeof(bintab)/sizeof(*bintab), 691 NULL, 0, 692 NULL, 0, 693 NULL, 0, 694 0 695}; 696 697/* The load/unload routines required by the zsh library interface */ 698 699/**/ 700int 701setup_(UNUSED(Module m)) 702{ 703 return 0; 704} 705 706/**/ 707int 708features_(Module m, char ***features) 709{ 710 *features = featuresarray(m, &module_features); 711 return 0; 712} 713 714/**/ 715int 716enables_(Module m, int **enables) 717{ 718 return handlefeatures(m, &module_features, enables); 719} 720 721/**/ 722int 723boot_(Module m) 724{ 725 ztcp_sessions = znewlinklist(); 726 return 0; 727} 728 729 730/**/ 731int 732cleanup_(Module m) 733{ 734 tcp_cleanup(); 735 freelinklist(ztcp_sessions, (FreeFunc) ztcp_free_session); 736 return setfeatureenables(m, &module_features, NULL); 737} 738 739/**/ 740int 741finish_(UNUSED(Module m)) 742{ 743 return 0; 744} 745