term.c revision 105:5440d7a4f376
1/* $Id$ */ 2/* $OpenBSD: netcat.c,v 1.57 2002/12/30 18:00:18 stevesk Exp $ */ 3/* 4 * Copyright (c) 2001 Eric Jackson <ericj@monkey.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30#include <sys/types.h> 31#include <sys/socket.h> 32#include <sys/termios.h> 33#include <sys/time.h> 34#include <sys/un.h> 35 36#include <netinet/in.h> 37#include <arpa/telnet.h> 38 39#include <err.h> 40#include <errno.h> 41#include <netdb.h> 42#include <poll.h> 43#include <stdarg.h> 44#include <stdio.h> 45#include <stdlib.h> 46#include <string.h> 47#include <unistd.h> 48#include <fcntl.h> 49 50ssize_t atomicio(ssize_t (*)(), int, void *, size_t); 51void readwrite(int); 52int remote_connect(char *, char *, struct addrinfo); 53 54struct termios saved_ios; 55void raw_term(); 56void restore_term(); 57 58char progname[256]; 59void usage(int); 60 61int 62main(int argc, char *argv[]) 63{ 64 int ch, s, ret; 65 char *host, *port, *endp; 66 struct addrinfo hints; 67 socklen_t len; 68 69 ret = 1; 70 s = 0; 71 host = NULL; 72 port = NULL; 73 endp = NULL; 74 75 strncpy(progname, argv[0], sizeof progname); 76 77 /* Cruft to make sure options are clean, and used properly. */ 78 if (argc != 3 || !argv[1] || !argv[2]) 79 usage(1); 80 81 host = argv[1]; 82 port = argv[2]; 83 84 85 if (!isatty(STDIN_FILENO)) 86 errx(1, "not attached to a terminal"); 87 88 raw_term(); 89 90 /* Initialize addrinfo structure */ 91 memset(&hints, 0, sizeof(struct addrinfo)); 92 hints.ai_family = AF_UNSPEC; 93 hints.ai_socktype = SOCK_STREAM; 94 hints.ai_protocol = IPPROTO_TCP; 95 96 s = remote_connect(host, port, hints); 97 ret = 0; 98 readwrite(s); 99 100 if (s) 101 close(s); 102 103 exit(ret); 104} 105 106/* 107 * remote_connect() 108 * Return's a socket connected to a remote host. Properly bind's to a local 109 * port or source address if needed. Return's -1 on failure. 110 */ 111int 112remote_connect(char *host, char *port, struct addrinfo hints) 113{ 114 struct addrinfo *res, *res0; 115 int s, error; 116 117 if ((error = getaddrinfo(host, port, &hints, &res))) 118 errx(1, "getaddrinfo: %s", gai_strerror(error)); 119 120 res0 = res; 121 do { 122 if ((s = socket(res0->ai_family, res0->ai_socktype, 123 res0->ai_protocol)) < 0) 124 continue; 125 126 if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0) 127 break; 128 129 close(s); 130 s = -1; 131 } while ((res0 = res0->ai_next) != NULL); 132 133 freeaddrinfo(res); 134 135 return (s); 136} 137 138/* 139 * readwrite() 140 * Loop that polls on the network file descriptor and stdin. 141 */ 142void 143readwrite(int nfd) 144{ 145 struct pollfd pfd[2]; 146 char buf[BUFSIZ]; 147 int wfd = fileno(stdin), n, ret; 148 int lfd = fileno(stdout); 149 int escape = 0; 150 151 /* Setup Network FD */ 152 pfd[0].fd = nfd; 153 pfd[0].events = POLLIN; 154 155 /* Setup STDIN FD */ 156 pfd[1].fd = wfd; 157 pfd[1].events = POLLIN; 158 159 while (pfd[0].fd != -1) { 160 if ((n = poll(pfd, 2, -1)) < 0) { 161 close(nfd); 162 err(1, "Polling Error"); 163 } 164 165 if (n == 0) 166 return; 167 168 if (pfd[0].revents & POLLIN) { 169 if ((n = read(nfd, buf, sizeof(buf))) < 0) 170 return; 171 else if (n == 0) { 172 shutdown(nfd, SHUT_RD); 173 pfd[0].fd = -1; 174 pfd[0].events = 0; 175 } else { 176 if ((ret = atomicio(write, lfd, buf, n)) != n) 177 return; 178 } 179 } 180 181 if (pfd[1].revents & POLLIN) { 182 if ((n = read(wfd, buf, sizeof(buf))) < 0) 183 return; 184 else if (n == 0) { 185 shutdown(nfd, SHUT_WR); 186 pfd[1].fd = -1; 187 pfd[1].events = 0; 188 } else { 189 if (escape) { 190 char buf2[] = "~"; 191 if (*buf == '.') { 192 printf("quit!\n"); 193 return; 194 } 195 escape = 0; 196 if (*buf != '~' && 197 (ret = atomicio(write, nfd, buf2, 1)) != n) 198 return; 199 } else { 200 escape = (*buf == '~'); 201 if (escape) 202 continue; 203 } 204 205 if ((ret = atomicio(write, nfd, buf, n)) != n) 206 return; 207 } 208 } 209 } 210} 211 212void 213usage(int ret) 214{ 215 fprintf(stderr, "usage: %s hostname port\n", progname); 216 if (ret) 217 exit(1); 218} 219 220/* 221 * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. 222 * All rights reserved. 223 * 224 * Redistribution and use in source and binary forms, with or without 225 * modification, are permitted provided that the following conditions 226 * are met: 227 * 1. Redistributions of source code must retain the above copyright 228 * notice, this list of conditions and the following disclaimer. 229 * 2. Redistributions in binary form must reproduce the above copyright 230 * notice, this list of conditions and the following disclaimer in the 231 * documentation and/or other materials provided with the distribution. 232 * 233 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 234 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 235 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 236 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 237 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 238 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 239 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 240 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 241 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 242 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 243 */ 244 245/* 246 * ensure all of data on socket comes through. f==read || f==write 247 */ 248ssize_t 249atomicio(ssize_t (*f) (), int fd, void *_s, size_t n) 250{ 251 char *s = _s; 252 ssize_t res, pos = 0; 253 254 while (n > pos) { 255 res = (f) (fd, s + pos, n - pos); 256 switch (res) { 257 case -1: 258 if (errno == EINTR || errno == EAGAIN) 259 continue; 260 case 0: 261 return (res); 262 default: 263 pos += res; 264 } 265 } 266 return (pos); 267} 268 269/* 270 * Copyright (c) 2003 Nathan L. Binkert <binkertn@umich.edu> 271 * 272 * Permission to use, copy, modify, and distribute this software for any 273 * purpose with or without fee is hereby granted, provided that the above 274 * copyright notice and this permission notice appear in all copies. 275 * 276 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 277 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 278 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 279 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 280 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 281 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 282 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 283 */ 284 285void 286raw_term() 287{ 288 struct termios ios; 289 290 if (tcgetattr(STDIN_FILENO, &ios) < 0) 291 errx(1, "tcgetagttr\n"); 292 293 memcpy(&saved_ios, &ios, sizeof(struct termios)); 294 295 ios.c_iflag &= ~(ISTRIP|ICRNL|IGNCR|ICRNL|IXOFF|IXON); 296 ios.c_oflag &= ~(OPOST); 297 ios.c_oflag &= (ONLCR); 298 ios.c_lflag &= ~(ISIG|ICANON|ECHO); 299 ios.c_cc[VMIN] = 1; 300 ios.c_cc[VTIME] = 0; 301 302 if (tcsetattr(STDIN_FILENO, TCSANOW, &ios) < 0) 303 errx(1, "tcsetattr\n"); 304 305 atexit(restore_term); 306} 307 308void 309restore_term() 310{ 311 tcsetattr(STDIN_FILENO, TCSANOW, &saved_ios); 312} 313