diff options
Diffstat (limited to '')
| -rw-r--r-- | src/usr.bin/nc/netcat.c | 258 |
1 files changed, 211 insertions, 47 deletions
diff --git a/src/usr.bin/nc/netcat.c b/src/usr.bin/nc/netcat.c index e6ec97ed0f..a8e90186e9 100644 --- a/src/usr.bin/nc/netcat.c +++ b/src/usr.bin/nc/netcat.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: netcat.c,v 1.124 2014/10/26 13:59:30 millert Exp $ */ | 1 | /* $OpenBSD: netcat.c,v 1.125 2014/10/30 16:06:07 tedu Exp $ */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (c) 2001 Eric Jackson <ericj@monkey.org> | 3 | * Copyright (c) 2001 Eric Jackson <ericj@monkey.org> |
| 4 | * | 4 | * |
| @@ -64,6 +64,12 @@ | |||
| 64 | #define PORT_MAX_LEN 6 | 64 | #define PORT_MAX_LEN 6 |
| 65 | #define UNIX_DG_TMP_SOCKET_SIZE 19 | 65 | #define UNIX_DG_TMP_SOCKET_SIZE 19 |
| 66 | 66 | ||
| 67 | #define POLL_STDIN 0 | ||
| 68 | #define POLL_NETOUT 1 | ||
| 69 | #define POLL_NETIN 2 | ||
| 70 | #define POLL_STDOUT 3 | ||
| 71 | #define BUFSIZE 2048 | ||
| 72 | |||
| 67 | /* Command Line Options */ | 73 | /* Command Line Options */ |
| 68 | int dflag; /* detached, no stdin */ | 74 | int dflag; /* detached, no stdin */ |
| 69 | int Fflag; /* fdpass sock to stdout */ | 75 | int Fflag; /* fdpass sock to stdout */ |
| @@ -111,6 +117,8 @@ void set_common_sockopts(int); | |||
| 111 | int map_tos(char *, int *); | 117 | int map_tos(char *, int *); |
| 112 | void report_connect(const struct sockaddr *, socklen_t); | 118 | void report_connect(const struct sockaddr *, socklen_t); |
| 113 | void usage(int); | 119 | void usage(int); |
| 120 | ssize_t drainbuf(int, unsigned char *, size_t *); | ||
| 121 | ssize_t fillbuf(int, unsigned char *, size_t *); | ||
| 114 | 122 | ||
| 115 | int | 123 | int |
| 116 | main(int argc, char *argv[]) | 124 | main(int argc, char *argv[]) |
| @@ -390,7 +398,7 @@ main(int argc, char *argv[]) | |||
| 390 | &len); | 398 | &len); |
| 391 | if (connfd == -1) { | 399 | if (connfd == -1) { |
| 392 | /* For now, all errnos are fatal */ | 400 | /* For now, all errnos are fatal */ |
| 393 | err(1, "accept"); | 401 | err(1, "accept"); |
| 394 | } | 402 | } |
| 395 | if (vflag) | 403 | if (vflag) |
| 396 | report_connect((struct sockaddr *)&cliaddr, len); | 404 | report_connect((struct sockaddr *)&cliaddr, len); |
| @@ -729,68 +737,224 @@ local_listen(char *host, char *port, struct addrinfo hints) | |||
| 729 | * Loop that polls on the network file descriptor and stdin. | 737 | * Loop that polls on the network file descriptor and stdin. |
| 730 | */ | 738 | */ |
| 731 | void | 739 | void |
| 732 | readwrite(int nfd) | 740 | readwrite(int net_fd) |
| 733 | { | 741 | { |
| 734 | struct pollfd pfd[2]; | 742 | struct pollfd pfd[4]; |
| 735 | unsigned char buf[16 * 1024]; | 743 | int stdin_fd = STDIN_FILENO; |
| 736 | int n, wfd = fileno(stdin); | 744 | int stdout_fd = STDOUT_FILENO; |
| 737 | int lfd = fileno(stdout); | 745 | unsigned char netinbuf[BUFSIZE]; |
| 738 | int plen; | 746 | size_t netinbufpos = 0; |
| 739 | 747 | unsigned char stdinbuf[BUFSIZE]; | |
| 740 | plen = sizeof(buf); | 748 | size_t stdinbufpos = 0; |
| 741 | 749 | int n, num_fds, flags; | |
| 742 | /* Setup Network FD */ | 750 | ssize_t ret; |
| 743 | pfd[0].fd = nfd; | 751 | |
| 744 | pfd[0].events = POLLIN; | 752 | /* don't read from stdin if requested */ |
| 745 | 753 | if (dflag) | |
| 746 | /* Set up STDIN FD. */ | 754 | stdin_fd = -1; |
| 747 | pfd[1].fd = wfd; | 755 | |
| 748 | pfd[1].events = POLLIN; | 756 | /* stdin */ |
| 757 | pfd[POLL_STDIN].fd = stdin_fd; | ||
| 758 | pfd[POLL_STDIN].events = POLLIN; | ||
| 759 | |||
| 760 | /* network out */ | ||
| 761 | pfd[POLL_NETOUT].fd = net_fd; | ||
| 762 | pfd[POLL_NETOUT].events = 0; | ||
| 763 | |||
| 764 | /* network in */ | ||
| 765 | pfd[POLL_NETIN].fd = net_fd; | ||
| 766 | pfd[POLL_NETIN].events = POLLIN; | ||
| 767 | |||
| 768 | /* stdout */ | ||
| 769 | pfd[POLL_STDOUT].fd = stdout_fd; | ||
| 770 | pfd[POLL_STDOUT].events = 0; | ||
| 771 | |||
| 772 | while (1) { | ||
| 773 | /* both inputs are gone, buffers are empty, we are done */ | ||
| 774 | if (pfd[POLL_STDIN].fd == -1 && pfd[POLL_NETIN].fd == -1 | ||
| 775 | && stdinbufpos == 0 && netinbufpos == 0) { | ||
| 776 | close(net_fd); | ||
| 777 | return; | ||
| 778 | } | ||
| 779 | /* both outputs are gone, we can't continue */ | ||
| 780 | if (pfd[POLL_NETOUT].fd == -1 && pfd[POLL_STDOUT].fd == -1) { | ||
| 781 | close(net_fd); | ||
| 782 | return; | ||
| 783 | } | ||
| 784 | /* listen and net in gone, queues empty, done */ | ||
| 785 | if (lflag && pfd[POLL_NETIN].fd == -1 | ||
| 786 | && stdinbufpos == 0 && netinbufpos == 0) { | ||
| 787 | close(net_fd); | ||
| 788 | return; | ||
| 789 | } | ||
| 749 | 790 | ||
| 750 | while (pfd[0].fd != -1) { | 791 | /* help says -i is for "wait between lines sent". We read and |
| 792 | * write arbitrary amounts of data, and we don't want to start | ||
| 793 | * scanning for newlines, so this is as good as it gets */ | ||
| 751 | if (iflag) | 794 | if (iflag) |
| 752 | sleep(iflag); | 795 | sleep(iflag); |
| 753 | 796 | ||
| 754 | if ((n = poll(pfd, 2 - dflag, timeout)) < 0) { | 797 | /* poll */ |
| 755 | int saved_errno = errno; | 798 | num_fds = poll(pfd, 4, timeout); |
| 756 | close(nfd); | 799 | |
| 757 | errc(1, saved_errno, "Polling Error"); | 800 | /* treat poll errors */ |
| 801 | if (num_fds == -1) { | ||
| 802 | close(net_fd); | ||
| 803 | err(1, "polling error"); | ||
| 758 | } | 804 | } |
| 759 | 805 | ||
| 760 | if (n == 0) | 806 | /* timeout happened */ |
| 807 | if (num_fds == 0) | ||
| 761 | return; | 808 | return; |
| 762 | 809 | ||
| 763 | if (pfd[0].revents & (POLLIN|POLLHUP)) { | 810 | /* treat socket error conditions */ |
| 764 | if ((n = read(nfd, buf, plen)) < 0) | 811 | for (n = 0; n < 4; n++) { |
| 765 | return; | 812 | if (pfd[n].revents & (POLLERR|POLLNVAL)) { |
| 766 | else if (n == 0) { | 813 | pfd[n].fd = -1; |
| 767 | shutdown(nfd, SHUT_RD); | ||
| 768 | pfd[0].fd = -1; | ||
| 769 | pfd[0].events = 0; | ||
| 770 | } else { | ||
| 771 | if (tflag) | ||
| 772 | atelnet(nfd, buf, n); | ||
| 773 | if (atomicio(vwrite, lfd, buf, n) != n) | ||
| 774 | return; | ||
| 775 | } | 814 | } |
| 776 | } | 815 | } |
| 816 | /* reading is possible after HUP */ | ||
| 817 | if (pfd[POLL_STDIN].events & POLLIN && | ||
| 818 | pfd[POLL_STDIN].revents & POLLHUP && | ||
| 819 | ! (pfd[POLL_STDIN].revents & POLLIN)) | ||
| 820 | pfd[POLL_STDIN].fd = -1; | ||
| 821 | |||
| 822 | if (pfd[POLL_NETIN].events & POLLIN && | ||
| 823 | pfd[POLL_NETIN].revents & POLLHUP && | ||
| 824 | ! (pfd[POLL_NETIN].revents & POLLIN)) | ||
| 825 | pfd[POLL_NETIN].fd = -1; | ||
| 826 | |||
| 827 | if (pfd[POLL_NETOUT].revents & POLLHUP) { | ||
| 828 | if (Nflag) | ||
| 829 | shutdown(pfd[POLL_NETOUT].fd, SHUT_WR); | ||
| 830 | pfd[POLL_NETOUT].fd = -1; | ||
| 831 | } | ||
| 832 | /* if HUP, stop watching stdout */ | ||
| 833 | if (pfd[POLL_STDOUT].revents & POLLHUP) | ||
| 834 | pfd[POLL_STDOUT].fd = -1; | ||
| 835 | /* if no net out, stop watching stdin */ | ||
| 836 | if (pfd[POLL_NETOUT].fd == -1) | ||
| 837 | pfd[POLL_STDIN].fd = -1; | ||
| 838 | /* if no stdout, stop watching net in */ | ||
| 839 | if (pfd[POLL_STDOUT].fd == -1) { | ||
| 840 | if (pfd[POLL_NETIN].fd != -1) | ||
| 841 | shutdown(pfd[POLL_NETIN].fd, SHUT_RD); | ||
| 842 | pfd[POLL_NETIN].fd = -1; | ||
| 843 | } | ||
| 777 | 844 | ||
| 778 | if (!dflag && pfd[1].revents & (POLLIN|POLLHUP)) { | 845 | /* try to read from stdin */ |
| 779 | if ((n = read(wfd, buf, plen)) < 0) | 846 | if (pfd[POLL_STDIN].revents & POLLIN && stdinbufpos < BUFSIZE) { |
| 780 | return; | 847 | ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf, |
| 781 | else if (n == 0) { | 848 | &stdinbufpos); |
| 782 | if (Nflag) | 849 | /* error or eof on stdin - remove from pfd */ |
| 783 | shutdown(nfd, SHUT_WR); | 850 | if (ret == 0 || ret == -1) |
| 784 | pfd[1].fd = -1; | 851 | pfd[POLL_STDIN].fd = -1; |
| 785 | pfd[1].events = 0; | 852 | /* read something - poll net out */ |
| 786 | } else { | 853 | if (stdinbufpos > 0) |
| 787 | if (atomicio(vwrite, nfd, buf, n) != n) | 854 | pfd[POLL_NETOUT].events = POLLOUT; |
| 788 | return; | 855 | /* filled buffer - remove self from polling */ |
| 856 | if (stdinbufpos == BUFSIZE) | ||
| 857 | pfd[POLL_STDIN].events = 0; | ||
| 858 | } | ||
| 859 | /* try to write to network */ | ||
| 860 | if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) { | ||
| 861 | ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf, | ||
| 862 | &stdinbufpos); | ||
| 863 | if (ret == -1) | ||
| 864 | pfd[POLL_NETOUT].fd = -1; | ||
| 865 | /* buffer empty - remove self from polling */ | ||
| 866 | if (stdinbufpos == 0) | ||
| 867 | pfd[POLL_NETOUT].events = 0; | ||
| 868 | /* buffer no longer full - poll stdin again */ | ||
| 869 | if (stdinbufpos < BUFSIZE) | ||
| 870 | pfd[POLL_STDIN].events = POLLIN; | ||
| 871 | } | ||
| 872 | /* try to read from network */ | ||
| 873 | if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) { | ||
| 874 | ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf, | ||
| 875 | &netinbufpos); | ||
| 876 | if (ret == -1) | ||
| 877 | pfd[POLL_NETIN].fd = -1; | ||
| 878 | /* eof on net in - remove from pfd */ | ||
| 879 | if (ret == 0) { | ||
| 880 | shutdown(pfd[POLL_NETIN].fd, SHUT_RD); | ||
| 881 | pfd[POLL_NETIN].fd = -1; | ||
| 789 | } | 882 | } |
| 883 | /* read something - poll stdout */ | ||
| 884 | if (netinbufpos > 0) | ||
| 885 | pfd[POLL_STDOUT].events = POLLOUT; | ||
| 886 | /* filled buffer - remove self from polling */ | ||
| 887 | if (netinbufpos == BUFSIZE) | ||
| 888 | pfd[POLL_NETIN].events = 0; | ||
| 889 | /* handle telnet */ | ||
| 890 | if (tflag) | ||
| 891 | atelnet(pfd[POLL_NETIN].fd, netinbuf, | ||
| 892 | netinbufpos); | ||
| 893 | } | ||
| 894 | /* try to write to stdout */ | ||
| 895 | if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) { | ||
| 896 | ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf, | ||
| 897 | &netinbufpos); | ||
| 898 | if (ret == -1) | ||
| 899 | pfd[POLL_STDOUT].fd = -1; | ||
| 900 | /* buffer empty - remove self from polling */ | ||
| 901 | if (netinbufpos == 0) | ||
| 902 | pfd[POLL_STDOUT].events = 0; | ||
| 903 | /* buffer no longer full - poll net in again */ | ||
| 904 | if (netinbufpos < BUFSIZE) | ||
| 905 | pfd[POLL_NETIN].events = POLLIN; | ||
| 906 | } | ||
| 907 | |||
| 908 | /* stdin gone and queue empty? */ | ||
| 909 | if (pfd[POLL_STDIN].fd == -1 && stdinbufpos == 0) { | ||
| 910 | if (pfd[POLL_NETOUT].fd != -1 && Nflag) | ||
| 911 | shutdown(pfd[POLL_NETOUT].fd, SHUT_WR); | ||
| 912 | pfd[POLL_NETOUT].fd = -1; | ||
| 913 | } | ||
| 914 | /* net in gone and queue empty? */ | ||
| 915 | if (pfd[POLL_NETIN].fd == -1 && netinbufpos == 0) { | ||
| 916 | pfd[POLL_STDOUT].fd = -1; | ||
| 790 | } | 917 | } |
| 791 | } | 918 | } |
| 792 | } | 919 | } |
| 793 | 920 | ||
| 921 | ssize_t | ||
| 922 | drainbuf(int fd, unsigned char *buf, size_t *bufpos) | ||
| 923 | { | ||
| 924 | ssize_t n; | ||
| 925 | ssize_t adjust; | ||
| 926 | |||
| 927 | n = write(fd, buf, *bufpos); | ||
| 928 | /* don't treat EAGAIN, EINTR as error */ | ||
| 929 | if (n == -1 && (errno == EAGAIN || errno == EINTR)) | ||
| 930 | n = -2; | ||
| 931 | if (n <= 0) | ||
| 932 | return n; | ||
| 933 | /* adjust buffer */ | ||
| 934 | adjust = *bufpos - n; | ||
| 935 | if (adjust > 0) | ||
| 936 | memmove(buf, buf + n, adjust); | ||
| 937 | *bufpos -= n; | ||
| 938 | return n; | ||
| 939 | } | ||
| 940 | |||
| 941 | |||
| 942 | ssize_t | ||
| 943 | fillbuf(int fd, unsigned char *buf, size_t *bufpos) | ||
| 944 | { | ||
| 945 | size_t num = BUFSIZE - *bufpos; | ||
| 946 | ssize_t n; | ||
| 947 | |||
| 948 | n = read(fd, buf + *bufpos, num); | ||
| 949 | /* don't treat EAGAIN, EINTR as error */ | ||
| 950 | if (n == -1 && (errno == EAGAIN || errno == EINTR)) | ||
| 951 | n = -2; | ||
| 952 | if (n <= 0) | ||
| 953 | return n; | ||
| 954 | *bufpos += n; | ||
| 955 | return n; | ||
| 956 | } | ||
| 957 | |||
| 794 | /* | 958 | /* |
| 795 | * fdpass() | 959 | * fdpass() |
| 796 | * Pass the connected file descriptor to stdout and exit. | 960 | * Pass the connected file descriptor to stdout and exit. |
