├── Makefile ├── README ├── icmpsh.c ├── icmpsh.h ├── icmpshd.c ├── openpty.c └── utils.c /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # icmpsh's Makefile 3 | # 4 | 5 | #====================================================== 6 | # chose your os type 7 | #====================================================== 8 | OS=-DMACOSX 9 | #OS=-DFREEBSD 10 | #OS=-DSOLARIS 11 | #OS=-DLINUX 12 | 13 | 14 | 15 | #-------------------------------------------------------------------------- 16 | # compile option 17 | #-------------------------------------------------------------------------- 18 | CC = gcc 19 | TAGS = ctags # for vi 20 | OPTIM = -O -pipe 21 | CFLAGS = $(OS) -pedantic -g -Wall $(OPTIM) 22 | LDFLAGS = # nothing 23 | 24 | #-------------------------------------------------------------------------- 25 | # include and library 26 | #-------------------------------------------------------------------------- 27 | INCDIRS = -I./ 28 | 29 | #-------------------------------------------------------------------------- 30 | # target and dependency 31 | #-------------------------------------------------------------------------- 32 | COMMON_SRC = openpty.c utils.c 33 | CLIENT_SRC = icmpsh.c $(COMMON_SRC) 34 | SERVER_SRC = icmpshd.c $(COMMON_SRC) 35 | COMMON_OBJ = openpty.o utils.o 36 | CLIENT_OBJ = $(COMMON_OBJ) icmpsh.o 37 | SERVER_OBJ = $(COMMON_OBJ) icmpshd.o 38 | 39 | CLIENT_TARGET = icmpsh 40 | SERVER_TARGET = icmpshd 41 | TARGET = $(CLIENT_TARGET) $(SERVER_TARGET) 42 | 43 | 44 | #-------------------------------------------------------------------------- 45 | # linked library handling 46 | #-------------------------------------------------------------------------- 47 | ifneq ($(findstring -DSOLARIS,$(OS)),) 48 | SYSLIBS= -lsocket -lnsl 49 | endif 50 | ifneq ($(findstring -DFREEBSD,$(OS)),) 51 | # SYSLIBS= -lutil 52 | SYSLIBS= 53 | endif 54 | ifneq ($(findstring -DMACOSX,$(OS)),) 55 | SYSLIBS= 56 | endif 57 | 58 | 59 | #-------------------------------------------------------------------------- 60 | # rule 61 | #-------------------------------------------------------------------------- 62 | 63 | all: $(TARGET) 64 | 65 | $(CLIENT_TARGET): $(CLIENT_OBJ) 66 | $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(INCDIRS) $(SYSLIBS) 67 | 68 | $(SERVER_TARGET): $(SERVER_OBJ) 69 | $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(INCDIRS) $(SYSLIBS) 70 | 71 | clean: 72 | rm -f $(TARGET) *.exe *.o core.* tags .gdb* 73 | 74 | ctags: 75 | ctags *.c *.h 76 | 77 | etags: 78 | etags *.c *.h 79 | 80 | .c.o: 81 | $(CC) -c -o $@ $(CFLAGS) $(INCDIRS) $^ 82 | 83 | # end of makefile 84 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | = ICMPSH PROJECT = 2 | 3 | icmpsh provides an interface to use terminal on icmp instead of tcp, using raw socket. 4 | 5 | 6 | = PREPARATION (HOW TO BUILD THIS PROGRAM) = 7 | 8 | just type 'make' on terminal. 9 | 10 | 11 | = PROGRAMS = 12 | 13 | icmpshd server program 14 | icmpsh client program 15 | 16 | 17 | = HOW TO USE = 18 | 19 | - icmpshd 20 | this program needs root privilege, so that have to type the following with sudo, 21 | 22 | bash$ sudo ./icmpshd 23 | 24 | if binding local address, which means "127.0.0.1" or "localhost", just type the above, 25 | but in case of binding another ip address, specify ip address as the following, 26 | 27 | bash$ sudo ./icmpshd -i 192.168.9.2 28 | 29 | as default icmpshd runs background without any messages on your terminal, if want to run it 30 | as foreground process to check debug information, use "-d" flag as the following, 31 | 32 | bash$ sudo ./icmpshd -d -i 192.168.9.2 33 | 34 | 35 | - icmpsh 36 | in case of using on local host only, just type the following, 37 | 38 | bash$ ./icmpsh 39 | 40 | if connecting remote icmpshd, specify icmpshd server's ip address, 41 | 42 | bash$ ./icmpsh 192.168.9.2 43 | 44 | -------------------------------------------------------------------------------- /icmpsh.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006 Tsuyoshi SAKAMOTO , 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 19 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 20 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 23 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 26 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 27 | * DAMAGE. 28 | */ 29 | 30 | 31 | /******************************************** 32 | * include file 33 | ******************************************** 34 | */ 35 | #include "icmpsh.h" 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include 43 | 44 | #include 45 | #include 46 | 47 | #include 48 | #include 49 | #include 50 | 51 | #include 52 | 53 | #include 54 | 55 | #include 56 | #include 57 | #include 58 | #include 59 | 60 | #include 61 | 62 | #include 63 | 64 | #include 65 | #ifdef SOLARIS 66 | #include 67 | #include 68 | #endif 69 | 70 | 71 | /******************************************** 72 | * macro 73 | ******************************************** 74 | */ 75 | #define DEFAULT_IP "127.0.0.1" 76 | 77 | 78 | 79 | /******************************************** 80 | * type definition 81 | ******************************************** 82 | */ 83 | 84 | /* 85 | * for short-cut 86 | */ 87 | typedef struct sockaddr SA; 88 | typedef struct sockaddr_in SA_IN; 89 | typedef struct in_addr ADDR; 90 | 91 | 92 | /* 93 | * options 94 | */ 95 | typedef struct _opt { 96 | int echo; 97 | char *psrc; 98 | char *pdst; 99 | SA *src; 100 | socklen_t srclen; 101 | SA *dst; 102 | socklen_t dstlen; 103 | pid_t pid; 104 | int timeout; 105 | } OPT; 106 | 107 | 108 | 109 | /******************************************** 110 | * global variable 111 | ******************************************** 112 | */ 113 | int debug = 0; 114 | 115 | static char *program = NULL; 116 | 117 | /* options */ 118 | static OPT *opt; 119 | 120 | /* raw socket */ 121 | static int sockin = -1; 122 | static int sockout = -1; 123 | 124 | /* network and tty buffer */ 125 | static bufset netbuf; 126 | static bufset termbuf; 127 | 128 | 129 | 130 | /******************************************** 131 | * proto type 132 | ******************************************** 133 | */ 134 | 135 | 136 | /*============================================================================ 137 | * program section 138 | *============================================================================ 139 | */ 140 | /*------------------------------------------------------------------------- 141 | * print usage and die 142 | *------------------------------------------------------------------------- 143 | */ 144 | void 145 | ic_print_usage(void) { 146 | fprintf(stdout, "usage: %s [option(s)] target\n" 147 | "\t[-d] print debug information \n" 148 | "\t[-i host] binding interface [not implemented] \n" 149 | "\t[-q] use icmp-echo and reply (reply only by default) \n" 150 | "\t[-t sec] session timeout \n", 151 | program); 152 | 153 | exit(1); 154 | } 155 | 156 | 157 | /*------------------------------------------------------------------------- 158 | * set option 159 | *------------------------------------------------------------------------- 160 | */ 161 | void 162 | ic_option(int argc, char **argv) { 163 | int ch; 164 | struct addrinfo dst_hints, src_hints; 165 | struct addrinfo *dst, *src; 166 | int out; 167 | 168 | opt = xmalloc(sizeof(OPT)); 169 | 170 | program = xstrdup(basename(argv[0])); 171 | opt->psrc = DEFAULT_IP; 172 | opt->pdst = DEFAULT_IP; 173 | opt->pid = getpid(); 174 | opt->timeout = IC_TIMEOUT; 175 | 176 | while ((ch = getopt(argc, argv, "dhiqt:")) != -1) { 177 | switch(ch) { 178 | case 'd': 179 | debug = 1; 180 | break; 181 | case 'h': 182 | ic_print_usage(); 183 | break; 184 | case 'i': 185 | opt->psrc = xstrdup(optarg); 186 | break; 187 | case 'q': 188 | opt->echo = 1; 189 | break; 190 | case 't': 191 | if ((out = atoi(optarg)) > 0 && out < IC_TIMEOUT) 192 | opt->timeout = out; 193 | break; 194 | default: 195 | ic_print_usage(); 196 | break; 197 | } 198 | } 199 | 200 | argc -= optind; 201 | argv += optind; 202 | if (argc) 203 | opt->pdst = xstrdup(*argv); 204 | 205 | /* 206 | * get host info 207 | */ 208 | memset(&dst_hints, 0, sizeof(dst_hints)); 209 | dst_hints.ai_flags = AI_CANONNAME; 210 | dst_hints.ai_family = AF_INET; 211 | dst_hints.ai_socktype = SOCK_RAW; 212 | if (getaddrinfo(opt->pdst, (char *)NULL, &dst_hints, &dst) != 0) { 213 | ic_log("getaddrinfo() failure, destination"); 214 | exit (1); 215 | } 216 | opt->dst = dst->ai_addr; 217 | opt->dstlen = dst->ai_addrlen; 218 | 219 | memset(&src_hints, 0, sizeof(src_hints)); 220 | src_hints.ai_flags = AI_CANONNAME; 221 | src_hints.ai_family = AF_INET; 222 | src_hints.ai_socktype = SOCK_RAW; 223 | if (getaddrinfo(opt->psrc, (char *)NULL, &src_hints, &src) != 0) { 224 | ic_log("getaddrinfo() failure, source"); 225 | exit (1); 226 | } 227 | opt->src = src->ai_addr; 228 | opt->srclen = src->ai_addrlen; 229 | 230 | return; 231 | } 232 | 233 | 234 | /*------------------------------------------------------------------------- 235 | * write to network 236 | * 237 | *------------------------------------------------------------------------- 238 | */ 239 | int 240 | ic_write_network(bufset *nbuf) { 241 | int iclen; 242 | ic_data dg; 243 | icmp_echo *picmph = &(dg.icmph); 244 | int send; 245 | u_short pid = opt->pid; 246 | 247 | /* 248 | * if size of netbuf is bigger than IC_REALPAYLOAD(ic_data's 249 | * payload), it has to split a netbuf in two (or more). 250 | */ 251 | while (nbuf->len > 0) { 252 | if (nbuf->len > IC_REALPAYLOAD) { 253 | iclen = IC_REALPAYLOAD; 254 | nbuf->len -= IC_REALPAYLOAD; 255 | } 256 | else { 257 | iclen = nbuf->len; 258 | nbuf->len = 0; 259 | } 260 | memset(&dg, 0, sizeof(dg)); 261 | ic_set_data(&dg, IC_REQ, IC_NORMAL, iclen, nbuf->buf, iclen); 262 | ic_set_header(&dg, ICMP_REQ, 0, pid, IC_TAG); 263 | for (;;) { 264 | send = sendto(sockout, (icmp_echo *)picmph, IC_DATASIZE, 0, opt->dst, opt->dstlen); 265 | if (send < 0) { 266 | if (errno == ENOBUFS) 267 | continue; 268 | ic_log("-> can not send packet (%s)", strerror(errno)); 269 | return (-1); 270 | } 271 | else if (send == IC_DATASIZE) { 272 | break; 273 | } 274 | ic_log("-> invalid data size sent, retry to send"); 275 | } 276 | } 277 | 278 | return (0); 279 | } 280 | 281 | 282 | /*------------------------------------------------------------------------- 283 | * write to tty 284 | * 285 | *------------------------------------------------------------------------- 286 | */ 287 | int 288 | ic_write_tty(bufset *tbuf) { 289 | (void) xwrite(STDOUT_FILENO, tbuf->buf, tbuf->len); 290 | tbuf->len = 0; 291 | return (0); 292 | } 293 | 294 | /*------------------------------------------------------------------------- 295 | * read from tty 296 | * 297 | *------------------------------------------------------------------------- 298 | */ 299 | int 300 | ic_read_tty(bufset *nbuf) { 301 | int cc; 302 | u_char tempbuff[BUFSIZ]; 303 | 304 | for (;;) { 305 | cc = read(STDIN_FILENO, tempbuff, nbuf->bufsz); 306 | if (cc < 0) { 307 | if (errno == EINTR) 308 | continue; 309 | else 310 | return (0); 311 | } 312 | else 313 | break; 314 | } 315 | 316 | if (cc > 0 && tempbuff[0] == ESCAPE) 317 | return (-1); /* quit immediately */ 318 | else { 319 | if ((nbuf->len + cc) > nbuf->bufsz) { 320 | nbuf->bufsz *= 2; 321 | nbuf->buf = xrealloc(nbuf->buf, nbuf->bufsz); 322 | ic_log("-> expand netbuf (%d)", nbuf->bufsz); 323 | } 324 | memcpy(nbuf->buf + nbuf->len, tempbuff, cc); 325 | nbuf->len += cc; 326 | } 327 | 328 | return (cc); 329 | } 330 | 331 | /*------------------------------------------------------------------------- 332 | # read from network 333 | * 334 | *------------------------------------------------------------------------- 335 | */ 336 | u_char 337 | ic_is_icmpsh_client(ic_data *p, u_short pid) { 338 | u_char type; 339 | 340 | if (p->iph.ip_hl != IC_IPHLWRS) 341 | return (IC_RESERVE); 342 | 343 | if (p->icmph.type == ICMP_ECHOREPLY && 344 | p->icmph.id == pid && 345 | p->icmph.seq == IC_TAG) 346 | type = p->data.ich.type; 347 | else 348 | return (IC_RESERVE); 349 | 350 | ic_log("dg.iph.ip_src (%s)", inet_ntoa(p->iph.ip_src)); 351 | ic_log("dg.iph.ip_dst (%s)", inet_ntoa(p->iph.ip_dst)); 352 | ic_log("dg.icmph.type (%d)", p->icmph.type); 353 | ic_log("dg.icmph.code (%d)", p->icmph.code); 354 | ic_log("dg.icmph.id (%d)", p->icmph.id); 355 | ic_log("dg.icmph.seq (%d)", p->icmph.seq); 356 | ic_log("dg.data.ich.type (%d)", p->data.ich.type); 357 | 358 | if (type == IC_REPLY || type == IC_EOT) 359 | return (type); 360 | 361 | return (IC_RESERVE); 362 | } 363 | 364 | int 365 | ic_read_network(bufset *tbuf) { 366 | ic_data dg; 367 | ic_header *pich = &(dg.data.ich); 368 | u_char *ppayload = (u_char *)&(dg.data.payload[0]) + sizeof(ic_header); 369 | int recv; /* length of ip datagram */ 370 | u_short pid = opt->pid; 371 | u_char type; 372 | SA_IN src; 373 | socklen_t srclen; 374 | 375 | for (;;) { 376 | memset(&dg, 0, sizeof(dg)); 377 | recv = recvfrom(sockin, (ic_data *)&dg, sizeof(dg), 0, (SA *)&src, &srclen); 378 | if (recv == IC_IPSIZE) { 379 | ic_recv_ntohs(&dg); 380 | if ((type = ic_is_icmpsh_client(&dg, pid)) == IC_REPLY) { 381 | if ((tbuf->len + pich->length) > tbuf->bufsz) { 382 | tbuf->bufsz *= 2; 383 | tbuf->buf = xrealloc(tbuf->buf, tbuf->bufsz); 384 | ic_log("-> expand termbuf (%d)", tbuf->bufsz); 385 | } 386 | ic_log("-> accepted data (%d)", pich->length); 387 | strncpy((char *)(tbuf->buf + tbuf->len), (char *)ppayload, pich->length); 388 | tbuf->len += pich->length; 389 | return (0); 390 | } 391 | else if (type == IC_EOT) { 392 | ic_log("quit, due to receiving IC_EOT"); 393 | return (-1); 394 | } 395 | ic_log("mismatch icmpsh packet, ignored"); 396 | continue; 397 | } 398 | else if (recv < 0) { 399 | if (errno == EINTR) 400 | continue; 401 | ic_log("-> error occurd, ignore incoming packet"); 402 | break; 403 | } 404 | ic_log("-> non-icmpsh data received, ignored"); 405 | break; 406 | } 407 | 408 | return (0); 409 | } 410 | 411 | 412 | /*------------------------------------------------------------------------- 413 | * icmpsh start and finish handshake 414 | * 415 | *------------------------------------------------------------------------- 416 | */ 417 | 418 | /* 419 | * interface of sending, receiving handshake packet 420 | * success, return value 0 421 | * fail, return value -1 422 | * recoverable fail, return value 1 423 | */ 424 | int 425 | ic_handshake_sendto(icmp_echo *p) { 426 | int cc; 427 | int retry; 428 | 429 | for (retry = 0; retry < 5; ++retry) { 430 | cc = sendto(sockout, p, IC_DATASIZE, 0, opt->dst, opt->dstlen); 431 | if (cc < 0) { 432 | ic_log("-> handshake_1 failure (%s)", strerror(errno)); 433 | if (errno == ENOBUFS) 434 | sleep (3); 435 | else 436 | return (-1); 437 | } 438 | else if (cc == IC_DATASIZE) { 439 | return (0); /* success */ 440 | } 441 | ic_log("-> invalid data sent, retry to send"); 442 | } 443 | 444 | /* fail */ 445 | return (1); 446 | } 447 | 448 | int 449 | ic_handshake_recvfrom(ic_data *p, u_char type) { 450 | int recv; 451 | int retry; 452 | u_short pid = opt->pid; 453 | SA_IN src; 454 | socklen_t srclen; 455 | ic_data dg; 456 | 457 | for (retry = 0; retry < 5; ++retry) { 458 | if (ic_select(sockin, IC_TIMEOUT) <= 0) 459 | break; 460 | memset(&dg, 0, sizeof(dg)); 461 | recv = recvfrom(sockin, (ic_data *)&dg, sizeof(dg), 0, (SA *)&src, &srclen); 462 | if (recv < 0) { 463 | ic_log("-> handshake_2 failure(%s)", strerror(errno)); 464 | if (errno == EINTR) 465 | sleep (3); 466 | else 467 | return (-1); 468 | } 469 | else if (recv == IC_IPSIZE) { 470 | ic_recv_ntohs(&dg); 471 | if (dg.icmph.type == ICMP_ECHOREPLY && 472 | dg.icmph.id == pid && 473 | dg.icmph.seq == IC_TAG && 474 | dg.data.ich.type == type) { 475 | ic_log("-> received ack from (%s)", inet_ntoa(dg.iph.ip_src)); 476 | *p = dg; 477 | return (0); 478 | } 479 | } 480 | ic_log("-> invalid data received, retry to receive"); 481 | } 482 | 483 | /* fail */ 484 | return (1); 485 | } 486 | 487 | int 488 | ic_start(struct winsize *pw) { 489 | ic_data sdg, rdg; 490 | icmp_echo *psdg = (icmp_echo *)&(sdg.icmph); 491 | u_short pid = opt->pid; 492 | int retry; 493 | 494 | ic_log("-> starting icmsh, opened socket (in:%d, out:%d)", sockin, sockout); 495 | 496 | memset(&sdg, 0, sizeof(sdg)); 497 | ic_set_data(&sdg, IC_START, IC_NORMAL, 0, NULL, 0); 498 | if (pw) { 499 | sdg.data.ich.tmflag |= IC_WNCHANG; 500 | ic_set_winsz(&(sdg.data.ich.opt.nwinsz), pw); 501 | } 502 | ic_set_header(&sdg, ICMP_REQ, 0, pid, IC_TAG); 503 | 504 | for (retry = 0; retry < 5; ++retry) { 505 | int sc, rc; 506 | if ((sc = ic_handshake_sendto(psdg)) == -1) 507 | break; 508 | else if (sc == 1) 509 | continue; 510 | 511 | memset(&rdg, 0, sizeof(rdg)); 512 | if ((rc = ic_handshake_recvfrom(&rdg, IC_START_ACK)) == -1) 513 | break; 514 | else if (rc == 0) 515 | return (0); 516 | ic_log("-> retry to send starting packet [%d]", retry); 517 | } 518 | 519 | return (-1); 520 | } 521 | 522 | int 523 | ic_finish(void) { 524 | ic_data sdg, rdg; 525 | icmp_echo *psdg = (icmp_echo *)&(sdg.icmph); 526 | u_short pid = opt->pid; 527 | int retry; 528 | 529 | ic_log("-> finishing icmsh"); 530 | 531 | memset(&sdg, 0, sizeof(sdg)); 532 | ic_set_data(&sdg, IC_QUIT, IC_NORMAL, 0, NULL, 0); 533 | ic_set_header(&sdg, ICMP_REQ, 0, pid, IC_TAG); 534 | 535 | for (retry = 0; retry < 5; ++retry) { 536 | int sc, rc; 537 | if ((sc = ic_handshake_sendto(psdg)) == -1) 538 | break; 539 | else if (sc == 1) 540 | continue; 541 | 542 | memset(&rdg, 0, sizeof(rdg)); 543 | if ((rc = ic_handshake_recvfrom(&rdg, IC_QUIT_ACK)) == -1 ) 544 | break; 545 | else if (rc == 0) 546 | return (0); 547 | ic_log("-> retry to send finishing packet [%d]", retry); 548 | } 549 | 550 | return (-1); 551 | } 552 | 553 | 554 | /*------------------------------------------------------------------------- 555 | * signal hander 556 | *------------------------------------------------------------------------- 557 | */ 558 | 559 | /* 560 | * send sigquit, CTRL-\ 561 | */ 562 | void 563 | ic_sendquit(int signo) { 564 | static u_char payload[BUFSIZ] = { IAC, ABORT, 0 }; 565 | bufset urgebuf = { payload, sizeof(payload), 2 }; 566 | (void) ic_write_network(&urgebuf); 567 | return; 568 | } 569 | 570 | void 571 | ic_catch_sigquit(void) { 572 | struct sigaction act, oact; 573 | 574 | act.sa_handler = ic_sendquit; 575 | sigemptyset(&act.sa_mask); 576 | act.sa_flags = 0; 577 | 578 | if (sigaction(SIGQUIT, &act, &oact) < 0) 579 | ic_log("can not set signal hander SIGQUIT"); 580 | 581 | return; 582 | } 583 | 584 | /* 585 | * send sigint, CTRL-C 586 | */ 587 | void 588 | ic_sendint(int signo) { 589 | static u_char payload[BUFSIZ] = { IAC, IP, 0 }; 590 | bufset urgebuf = { payload, sizeof(payload), 2 }; 591 | (void) ic_write_network(&urgebuf); 592 | return; 593 | } 594 | 595 | void 596 | ic_catch_sigint(void) { 597 | struct sigaction act, oact; 598 | 599 | act.sa_handler = ic_sendint; 600 | sigemptyset(&act.sa_mask); 601 | act.sa_flags = 0; 602 | 603 | if (sigaction(SIGINT, &act, &oact) < 0) 604 | ic_log("can not set signal hander SIGINT"); 605 | 606 | return; 607 | } 608 | 609 | /* 610 | * send sigtstp, CTRL-Z 611 | */ 612 | void 613 | ic_sendtstp(int signo) { 614 | static u_char payload[BUFSIZ] = { IAC, SUSP, 0 }; 615 | bufset urgebuf = { payload, sizeof(payload), 2 }; 616 | (void) ic_write_network(&urgebuf); 617 | return; 618 | } 619 | 620 | void 621 | ic_catch_sigtstp(void) { 622 | struct sigaction act, oact; 623 | 624 | act.sa_handler = ic_sendtstp; 625 | sigemptyset(&act.sa_mask); 626 | act.sa_flags = 0; 627 | 628 | if (sigaction(SIGTSTP, &act, &oact) < 0) 629 | ic_log("can not set signal hander SIGTSTP"); 630 | 631 | return; 632 | } 633 | 634 | 635 | void 636 | ic_signal() { 637 | ic_catch_sigquit(); 638 | ic_catch_sigint(); 639 | ic_catch_sigtstp(); 640 | 641 | return; 642 | } 643 | 644 | 645 | /*------------------------------------------------------------------------- 646 | * main 647 | *------------------------------------------------------------------------- 648 | */ 649 | void 650 | ic_original_termios(struct termios *p) { 651 | (void) tcsetattr(STDIN_FILENO, TCSAFLUSH, p); 652 | return; 653 | } 654 | 655 | int 656 | ic_init_terminal(struct termios tt) { 657 | struct termios rtt = tt; 658 | int on = 1; 659 | 660 | rtt.c_lflag &= ~(ECHO|ICANON); 661 | rtt.c_cc[VMIN] = 1; 662 | rtt.c_cc[VTIME] = 0; 663 | if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &rtt) == -1) 664 | ic_log("tcsetattr error (%s)", strerror(errno)); 665 | 666 | if (ioctl(STDIN_FILENO, FIONBIO, (char *)&on) == -1) { 667 | ic_log("ioctl error stdin (%s)", strerror(errno)); 668 | return (-1); 669 | } 670 | if (ioctl(STDOUT_FILENO, FIONBIO, (char *)&on) == -1) { 671 | ic_log("ioctl error stdout (%s)", strerror(errno)); 672 | return (-1); 673 | } 674 | if (ioctl(sockin, FIONBIO, (char *)&on) == -1) { 675 | ic_log("ioctl error sockin (%s)", strerror(errno)); 676 | return (-1); 677 | } 678 | if (ioctl(sockout, FIONBIO, (char *)&on) == -1) { 679 | ic_log("ioctl error sockout (%s)", strerror(errno)); 680 | return (-1); 681 | } 682 | 683 | return (0); 684 | } 685 | 686 | void 687 | ic_make_buf() { 688 | netbuf.buf = xmalloc(IC_REALPAYLOAD); 689 | netbuf.bufsz = IC_REALPAYLOAD; 690 | netbuf.len = 0; 691 | termbuf.buf = xmalloc(IC_REALPAYLOAD); 692 | termbuf.bufsz = IC_REALPAYLOAD; 693 | termbuf.len = 0; 694 | ic_log("-> made buffer (netbuf: %d bytes)", netbuf.bufsz); 695 | ic_log("-> made buffer (termbuf: %d bytes)", termbuf.bufsz); 696 | 697 | return; 698 | } 699 | 700 | int 701 | main(int argc, char **argv) { 702 | int uid; 703 | int maxfd; 704 | fd_set rfd, wfd; 705 | struct termios tt; /* original termios */ 706 | struct winsize win; 707 | 708 | ic_option(argc, argv); 709 | 710 | if ((sockin = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) 711 | ic_log("socket failure in(%d)", sockin); 712 | if ((sockout = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) 713 | ic_log("socket failure out(%d)", sockout); 714 | 715 | /* renounce privilege */ 716 | if ((uid = getuid()) > 0) 717 | setuid(uid); 718 | 719 | if (isatty(STDIN_FILENO)) { 720 | if (tcgetattr(STDIN_FILENO, &tt) == -1) 721 | return (1); 722 | if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win) == -1) 723 | return (1); 724 | if (ic_init_terminal(tt) == -1) 725 | return (1); 726 | } 727 | else 728 | return (1); 729 | 730 | /* 731 | * main loop 732 | */ 733 | if (ic_start(&win) < 0) { 734 | ic_original_termios(&tt); 735 | return (1); 736 | } 737 | 738 | fprintf(stderr, "Start icmpsh, escape sequence is ^]\n"); 739 | ic_signal(); 740 | ic_make_buf(); 741 | 742 | maxfd = (sockin > sockout) ? sockin : sockout; 743 | FD_ZERO(&rfd); 744 | FD_ZERO(&wfd); 745 | for (;;) { 746 | int nfd; 747 | FD_ZERO(&wfd); 748 | if (netbuf.len > 0) 749 | FD_SET(sockout, &wfd); 750 | if (termbuf.len > 0) 751 | FD_SET(STDOUT_FILENO, &wfd); 752 | FD_SET(STDIN_FILENO, &rfd); 753 | FD_SET(sockin, &rfd); 754 | ic_log("-> waiting (in:%d, out:%d)", sockin, sockout); 755 | nfd = select(maxfd + 1, &rfd, &wfd, 0, 0); 756 | ic_log("-> return select() -> %d", nfd); 757 | if (nfd < 0 && errno != EINTR) 758 | break; 759 | if (nfd > 0 && netbuf.len > 0 && FD_ISSET(sockout, &wfd)) 760 | (void) ic_write_network(&netbuf); 761 | if (nfd > 0 && termbuf.len > 0 && FD_ISSET(STDOUT_FILENO, &wfd)) 762 | (void) ic_write_tty(&termbuf); 763 | if (nfd > 0 && FD_ISSET(STDIN_FILENO, &rfd)) { 764 | if (ic_read_tty(&netbuf) < 0) 765 | break; 766 | } 767 | if (nfd > 0 && FD_ISSET(sockin, &rfd)) { 768 | if (ic_read_network(&termbuf) < 0) 769 | break; 770 | } 771 | } 772 | 773 | if (ic_finish() < 0) { 774 | fprintf(stderr, "\nAbnormal finish icmpsh\n"); 775 | return (1); 776 | } 777 | 778 | ic_original_termios(&tt); 779 | 780 | fprintf(stderr, "\nFinish icmpsh, bye ;-)\n"); 781 | return (0); 782 | } 783 | 784 | /* end of source */ 785 | -------------------------------------------------------------------------------- /icmpsh.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006 Tsuyoshi SAKAMOTO , 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 19 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 20 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 23 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 26 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 27 | * DAMAGE. 28 | */ 29 | 30 | 31 | /******************************************** 32 | * include file 33 | ******************************************** 34 | */ 35 | 36 | /* include */ 37 | #include 38 | #include 39 | #include /* FreeBSD */ 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | 48 | 49 | /******************************************** 50 | * global type definition 51 | ******************************************** 52 | */ 53 | 54 | /* 55 | * netbuf & termbuf 56 | */ 57 | typedef struct _bufset { 58 | u_char *buf; 59 | int bufsz; 60 | int len; 61 | } bufset; 62 | 63 | 64 | 65 | /* 66 | * icmpsh data format 67 | * 68 | * ICMP 69 | * +----------+----------+----------+----------+ 70 | * | type(1) | code(1) | check sum(2) | 71 | * +----------+----------+----------+----------+ 72 | * | packet id(2) | sequece(2) | 73 | * +----------+----------+----------+----------+ 74 | * 75 | * ICMPSH HEADER 76 | * +----------+----------+----------+----------+ 77 | * | type(1) | flag(1) | tmpflag | reserve | 78 | * +----------+----------+----------+----------+ 79 | * | option(80) | 80 | * +----------+----------+----------+----------+ 81 | * | | 82 | * +----------+----------+----------+----------+ 83 | * | | length(2) | 84 | * +----------+----------+----------+----------+ 85 | * 86 | */ 87 | 88 | typedef struct _net_termios { /* struct termios */ 89 | u_long c_iflag; 90 | u_long c_oflag; 91 | u_long c_cflag; 92 | u_long c_lflag; 93 | u_char c_cc[48]; /* reference NCCS in termios.h */ 94 | u_long c_ispeed; 95 | u_long c_ospeed; 96 | } net_termios; 97 | 98 | typedef struct _net_winsz { /* struct winsize */ 99 | u_short ws_row; 100 | u_short ws_col; 101 | u_short ws_xpixel; 102 | u_short ws_ypixel; 103 | } net_winsz; 104 | 105 | typedef struct _icmp_echo { 106 | u_char type; 107 | u_char code; 108 | u_short cksum; 109 | u_short id; /* client process id */ 110 | u_short seq; /* IC_TAG field */ 111 | } icmp_echo; 112 | 113 | #define IC_IPHLWRS 5 /* number of ip header words (20 bytes) */ 114 | 115 | #define IC_BUFSIZE 512 /* ic */ 116 | #define IC_REALPAYLOAD (IC_BUFSIZE - sizeof(ic_header)) /* payload-ich */ 117 | #define IC_DATASIZE (sizeof(icmp_echo) + IC_BUFSIZE) /* icmp+ic */ 118 | #define IC_IPSIZE (IC_DATASIZE + (IC_IPHLWRS * 4)) /* ip+icmp+ic */ 119 | 120 | /* icmpsh header */ 121 | typedef struct _ic_header_option { 122 | net_termios ntermios; 123 | net_winsz nwinsz; 124 | } ic_header_opt; 125 | 126 | typedef struct _ic_header { 127 | u_char type; 128 | u_char flag; 129 | u_char tmflag; 130 | u_char reserve; 131 | ic_header_opt opt; 132 | u_short length; 133 | } ic_header; 134 | 135 | typedef struct _ic_data { 136 | struct ip iph; 137 | icmp_echo icmph; 138 | union { 139 | ic_header ich; 140 | u_char payload[IC_BUFSIZE]; 141 | } data; 142 | } ic_data; 143 | 144 | 145 | /* tag */ 146 | #define IC_TAG 0x1122 147 | 148 | /* icmpsh packet type */ 149 | #define IC_RESERVE 0x00 /* error handle */ 150 | #define IC_START 0x01 /* start session, make co-proc(shell) */ 151 | #define IC_START_ACK 0x02 /* ack of IC_START */ 152 | #define IC_REQ 0xa1 /* client command request */ 153 | #define IC_REPLY 0xb1 /* server command response */ 154 | #define IC_QUIT 0xe1 /* end session, kill co-proc(shell) */ 155 | #define IC_QUIT_ACK 0xe2 /* ack of IC_QUIT */ 156 | #define IC_EOT 0xf1 /* not implement */ 157 | 158 | /* flag */ 159 | #define IC_NORMAL 0x01 160 | #define IC_CONT 0x02 /* not implement */ 161 | #define IC_EOD 0x04 /* not implement */ 162 | 163 | /* termios */ 164 | #define IC_TMNOTCH 0x01 /* not changed */ 165 | #define IC_TMCHANG 0x02 /* changed */ 166 | #define IC_WNNOTCH 0x04 /* not changed */ 167 | #define IC_WNCHANG 0x08 /* changed */ 168 | 169 | /* misc */ 170 | #define IC_TIMEOUT 600 /* 600 seconds */ 171 | 172 | 173 | 174 | /******************************************** 175 | * constant number and string 176 | ******************************************** 177 | */ 178 | #define ESCAPE 29 /* escape character for icmpsh */ 179 | 180 | 181 | 182 | /******************************************** 183 | * misc macro 184 | ******************************************** 185 | */ 186 | 187 | /* 188 | * short cut 189 | */ 190 | #define ICMP_REQ ((opt->echo) ? ICMP_ECHO : ICMP_ECHOREPLY) 191 | 192 | 193 | /* 194 | * syslog's level for ic_plog() 195 | */ 196 | #define SEMR 0 197 | #define SALT 1 198 | #define SCRT 2 199 | #define SERR 3 200 | #define SWAR 4 201 | #define SNOT 5 202 | #define SINF 6 203 | #define SDEB 7 204 | #define SNOP 8 205 | 206 | 207 | 208 | /******************************************** 209 | * interface type definition 210 | ******************************************** 211 | */ 212 | 213 | 214 | /******************************************** 215 | * function 216 | ******************************************** 217 | */ 218 | 219 | /* 220 | * openpty.c 221 | */ 222 | extern int ptym_open(char *); 223 | extern int ptys_open(int, char *); 224 | 225 | 226 | /* 227 | * utils.c 228 | */ 229 | extern void ic_plog(int, const char *, ...); 230 | extern void ic_log(const char *, ...); 231 | extern int ic_select(int, long); 232 | 233 | #ifdef SOLARIS 234 | extern void cfmakeraw(struct termios *); 235 | #endif 236 | 237 | extern void ic_recv_ntohs(ic_data *); 238 | extern void ic_set_termios(net_termios *, struct termios *); 239 | extern void ic_set_winsz(net_winsz *, struct winsize *); 240 | extern void ic_get_termios(struct termios *, net_termios *); 241 | extern void ic_get_winsz(struct winsize *, net_winsz *); 242 | extern void ic_set_data(ic_data *, u_char, u_char, u_short, u_char *, int); 243 | extern void ic_set_header(ic_data *, u_char, u_char, u_short, u_short); 244 | 245 | extern int ic_kill(char *, pid_t, int); 246 | extern pid_t ic_waitpid(char *, pid_t, int *, int); 247 | 248 | extern ssize_t xread(int, void *, size_t); 249 | extern ssize_t xwrite(int, void *, size_t); 250 | 251 | extern void vsys_err(int, const char *, ...); 252 | extern void vsys(int, const char *, ...); 253 | 254 | extern unsigned short xchecksum(unsigned short *, int); 255 | 256 | extern pid_t xfork(void); 257 | 258 | extern void *xmalloc(size_t); 259 | extern void *xrealloc(void *, size_t); 260 | extern char *xstrdup(char *); 261 | 262 | /* end of header */ 263 | -------------------------------------------------------------------------------- /icmpshd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006 Tsuyoshi SAKAMOTO , 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 19 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 20 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 23 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 26 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 27 | * DAMAGE. 28 | */ 29 | 30 | 31 | /******************************************** 32 | * include file 33 | ******************************************** 34 | */ 35 | #include "icmpsh.h" 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include 43 | 44 | #include 45 | #include 46 | 47 | #include 48 | #include 49 | #include 50 | 51 | #include 52 | 53 | #include 54 | 55 | #include 56 | #include 57 | #include 58 | #include 59 | 60 | #include 61 | 62 | #include 63 | 64 | 65 | #include 66 | #ifdef SOLARIS 67 | #include 68 | #include 69 | #include 70 | #include 71 | #endif 72 | 73 | 74 | 75 | /******************************************** 76 | * macro 77 | ******************************************** 78 | */ 79 | #define MAXHOSTLEN 256 80 | #define MAXFD 256 81 | #define DEFAULT_DIR "/var/tmp" 82 | #define DEFAULT_PIDFILE "icmpshd.pid" 83 | #define DEFAULT_IP "127.0.0.1" 84 | #define DEFAULT_INTERVAL 1800 85 | 86 | #define MAXFD3(max, a, b, c) \ 87 | { \ 88 | max = (a > b) ? a : b; \ 89 | max = (max > c) ? max : c; \ 90 | } 91 | 92 | 93 | /******************************************** 94 | * type definition 95 | ******************************************** 96 | */ 97 | 98 | /* 99 | * for short-cut 100 | */ 101 | typedef struct sockaddr SA; 102 | typedef struct sockaddr_in SA_IN; 103 | typedef struct in_addr ADDR; 104 | 105 | 106 | /* 107 | * options 108 | */ 109 | typedef struct _opt { 110 | char *dir; 111 | char *ip; 112 | SA *src; 113 | socklen_t srclen; 114 | char *user; 115 | int fac; 116 | time_t timeout; 117 | struct termios origtt; 118 | char *pidfile; 119 | } OPT; 120 | 121 | 122 | /* 123 | * process database 124 | * 125 | * Process database stores informations, including remote host name, ip address, 126 | * and process id of icmpsh(NOT icmpshd), and keep it inside icmpshd to determine 127 | * which co-process icmpshd will transfer a datagram to. 128 | * 129 | */ 130 | typedef struct _proc_db { 131 | struct _proc_db *next; 132 | ADDR client; /* key(1): client ip address */ 133 | u_short id; /* key(2): process id of remote host */ 134 | pid_t shelldrv; /* key(3): child's pid (ic_shell_driver) */ 135 | char clientname[MAXHOSTLEN]; 136 | ADDR local; 137 | int fd; 138 | time_t create; /* create time */ 139 | time_t last; /* last access time */ 140 | } proc_db; 141 | 142 | 143 | 144 | /******************************************** 145 | * global variable 146 | ******************************************** 147 | */ 148 | int debug = 0; 149 | 150 | static char *program = NULL; 151 | 152 | static int sockin = -1; 153 | static int sockout = -1; 154 | 155 | 156 | /* 157 | * syslog facility and level 158 | */ 159 | const int facility[] = { 160 | LOG_LOCAL0, 161 | LOG_LOCAL1, 162 | LOG_LOCAL2, 163 | LOG_LOCAL3, 164 | LOG_LOCAL4, 165 | LOG_LOCAL5, 166 | LOG_LOCAL6, 167 | LOG_LOCAL7 168 | }; 169 | 170 | 171 | 172 | /******************************************** 173 | * proto type 174 | ******************************************** 175 | */ 176 | /* misc */ 177 | static void ic_print_usage(void); 178 | static OPT *ic_option(int, char **); 179 | static void ic_go_daemon(OPT *); 180 | 181 | /* signal handler for listener process */ 182 | static void ic_ignore_sighup(void); 183 | static void ic_sig_chld(int); 184 | static void ic_catch_status(void); 185 | 186 | /* process database utils */ 187 | static proc_db * ic_db_make_list(void); 188 | static void ic_db_lock(void); 189 | static void ic_db_unlock(void); 190 | static void ic_db_cleanup(void); 191 | static int ic_db_cleanup_old(time_t, time_t); 192 | static void ic_db_make(int); 193 | static int ic_db_nrecord(void); 194 | static proc_db * ic_db_insert(ic_data *, int); 195 | static proc_db * ic_db_remove(ic_data *); 196 | static proc_db * ic_db_find(ic_data *, int); 197 | static proc_db * ic_db_find_pid(pid_t); 198 | 199 | /* request handler */ 200 | static int ic_reply(u_char, proc_db *); 201 | static int ic_req_start(ic_data *, char **, OPT *); 202 | static int ic_req_req(ic_data *); 203 | static int ic_req_quit(ic_data *); 204 | 205 | 206 | /*============================================================================ 207 | * program section 208 | *============================================================================ 209 | */ 210 | 211 | /*------------------------------------------------------------------------- 212 | * print usage and die 213 | *------------------------------------------------------------------------- 214 | */ 215 | void 216 | ic_print_usage(void) { 217 | fprintf(stdout, "usage: %s [option(s)] target\n" 218 | "\t[-d] print debug information, not daemon mode \n" 219 | "\t[-f fac] syslog facility \n" 220 | "\t[-i ip] bind ip address \n" 221 | "\t[-p pid] change pid file \n" 222 | "\t[-r dir] change root directory \n" 223 | "\t[-t sec] internal database clean-up interval (for debug) \n", 224 | program); 225 | 226 | exit(1); 227 | } 228 | 229 | 230 | /*------------------------------------------------------------------------- 231 | * set option 232 | *------------------------------------------------------------------------- 233 | */ 234 | OPT * 235 | ic_option(int argc, char **argv) { 236 | OPT *opt; 237 | int ch; 238 | int i; 239 | struct addrinfo hints; 240 | struct addrinfo *src; 241 | 242 | opt = xmalloc(sizeof(OPT)); 243 | 244 | program = xstrdup(basename(argv[0])); 245 | opt->dir = DEFAULT_DIR; 246 | opt->ip = DEFAULT_IP; 247 | opt->fac = facility[0]; 248 | opt->timeout = DEFAULT_INTERVAL; 249 | opt->pidfile = DEFAULT_PIDFILE; 250 | 251 | if (tcgetattr(STDIN_FILENO, &(opt->origtt)) == -1) 252 | ic_plog(SDEB, "(main) tcgetattr error (%s)", strerror(errno)); 253 | 254 | while ((ch = getopt(argc, argv, "df:i:r:t:")) != -1) { 255 | switch(ch) { 256 | case 'd': 257 | debug = 1; 258 | break; 259 | case 'f': 260 | if (strlen(optarg) != 1 || !isdigit((int)optarg[0])) 261 | ic_print_usage(); 262 | i = atoi(optarg); 263 | if (i < 0 || i > 7) 264 | i = 0; 265 | opt->fac = facility[i]; 266 | break; 267 | case 'h': 268 | ic_print_usage(); 269 | break; 270 | case 'i': 271 | opt->ip = xstrdup(optarg); 272 | break; 273 | case 'p': 274 | opt->pidfile = xstrdup(optarg); 275 | break; 276 | case 'r': 277 | opt->dir = xstrdup(optarg); 278 | break; 279 | case 't': 280 | opt->timeout = (time_t)atoi(optarg); 281 | if (opt->timeout > (time_t)DEFAULT_INTERVAL) 282 | opt->timeout = DEFAULT_INTERVAL; 283 | break; 284 | default: 285 | ic_print_usage(); 286 | break; 287 | } 288 | } 289 | 290 | argc -= optind; 291 | argv += optind; 292 | if (argc) 293 | opt->ip = xstrdup(*argv); 294 | 295 | /* 296 | * get interface address 297 | */ 298 | memset(&hints, 0, sizeof(hints)); 299 | hints.ai_flags = AI_CANONNAME; 300 | hints.ai_family = AF_INET; 301 | hints.ai_socktype = SOCK_RAW; 302 | if (getaddrinfo(opt->ip, (char *)NULL, &hints, &src) != 0) 303 | ic_print_usage(); 304 | opt->src = src->ai_addr; 305 | opt->srclen = src->ai_addrlen; 306 | 307 | return opt; 308 | } 309 | 310 | 311 | /*------------------------------------------------------------------------- 312 | * put pid file 313 | *------------------------------------------------------------------------- 314 | */ 315 | void 316 | ic_put_pidfile(OPT *opt) { 317 | FILE *fp; 318 | char buf[BUFSIZ]; 319 | 320 | if (debug) 321 | return; 322 | 323 | if ((fp = fopen(opt->pidfile, "w")) == NULL) 324 | return; 325 | 326 | #ifdef SOLARIS 327 | snprintf(buf, sizeof(buf), "%lu\n", getpid()); 328 | #else 329 | snprintf(buf, sizeof(buf), "%d\n", getpid()); 330 | #endif 331 | fputs(buf, fp); 332 | fclose(fp); 333 | 334 | return; 335 | } 336 | 337 | 338 | /*------------------------------------------------------------------------- 339 | * signal handler 340 | *------------------------------------------------------------------------- 341 | */ 342 | void 343 | ic_ignore_sighup(void) { 344 | struct sigaction act, oact; 345 | 346 | act.sa_handler = SIG_IGN; 347 | sigemptyset(&act.sa_mask); 348 | act.sa_flags = 0; 349 | 350 | if (sigaction(SIGHUP, &act, &oact) < 0) 351 | ic_plog(SDEB, "(main) can not set signal handler"); 352 | 353 | return; 354 | } 355 | 356 | void 357 | ic_sig_chld(int signo) { 358 | pid_t tmp_pid = -1; 359 | pid_t pid = -1; 360 | int status; 361 | proc_db *ptr; 362 | 363 | while ((tmp_pid = waitpid(-1, &status, WNOHANG)) > 0) { 364 | pid = tmp_pid; 365 | ic_plog(SDEB, "(main) child co-process %d terminated", pid); 366 | } 367 | 368 | /* 369 | * reset session immediately 370 | */ 371 | if (pid > 0 && (ptr = ic_db_find_pid(pid)) != NULL) 372 | ic_reply(IC_EOT, ptr); 373 | 374 | return; 375 | } 376 | 377 | void 378 | ic_catch_status(void) { 379 | struct sigaction act, oact; 380 | 381 | act.sa_handler = ic_sig_chld; 382 | sigemptyset(&act.sa_mask); 383 | act.sa_flags = 0; 384 | 385 | if (sigaction(SIGCHLD, &act, &oact) < 0) 386 | ic_plog(SDEB, "(main) can not set signal handler"); 387 | 388 | return; 389 | } 390 | 391 | /*------------------------------------------------------------------------- 392 | * switch daemon mode 393 | *------------------------------------------------------------------------- 394 | */ 395 | void 396 | ic_go_daemon(OPT *opt) { 397 | int i; 398 | pid_t pid; 399 | 400 | if ((pid = xfork()) > 0) { 401 | exit(0); /* first parent exit */ 402 | } 403 | 404 | setsid(); /* get control terminal */ 405 | ic_ignore_sighup(); /* ignore hang-up signal */ 406 | ic_catch_status(); /* catch child process's status */ 407 | 408 | if ((pid = xfork()) > 0) { 409 | exit(0); /* second parent exit */ 410 | } 411 | 412 | if (chdir(opt->dir) < 0) { 413 | exit(1); 414 | } 415 | 416 | for (i = 0; i < MAXFD; ++i) { 417 | close(i); /* force to close all opened descriptors */ 418 | } 419 | 420 | return; 421 | } 422 | 423 | /*------------------------------------------------------------------------- 424 | * database interface 425 | * 426 | *------------------------------------------------------------------------- 427 | */ 428 | static proc_db *Proc_db = NULL; /* base element */ 429 | static int nrecord = 0; /* total number of element */ 430 | 431 | /* insert flag */ 432 | #define IC_DB_REMOVE 0x01 433 | #define IC_DB_UPDATE 0x02 434 | /* not needed 435 | #define IC_DB_INSERT 0x04 436 | */ 437 | 438 | 439 | /* local */ 440 | proc_db * 441 | ic_db_make_list(void) { 442 | return xmalloc(sizeof(proc_db)); 443 | } 444 | 445 | void 446 | ic_db_lock(void) { 447 | return; 448 | } 449 | 450 | void 451 | ic_db_unlock(void) { 452 | return; 453 | } 454 | 455 | /* public */ 456 | void 457 | ic_db_cleanup(void) { 458 | proc_db *ptr, *tmptr; 459 | if (Proc_db == NULL) 460 | return; 461 | 462 | ptr = Proc_db; 463 | do { 464 | tmptr = ptr->next; 465 | free(ptr); 466 | ptr = tmptr; 467 | } while (ptr); 468 | 469 | Proc_db = NULL; 470 | nrecord = 0; 471 | return; 472 | } 473 | 474 | int 475 | ic_db_cleanup_old(time_t now, time_t sec) { 476 | int nfree; 477 | proc_db *ptr, *prev; 478 | if (Proc_db == NULL) 479 | return (-1); 480 | 481 | nfree = 0; 482 | prev = Proc_db; 483 | ptr = prev->next; 484 | while (ptr) { 485 | if ((now - ptr->last) > sec) { 486 | proc_db *tmptr = ptr; 487 | ic_plog(SDEB, "(ic_db_cleanup_old) remove pid %d", ptr->id); 488 | ic_kill("ic_db_cleanup_old", ptr->shelldrv, SIGINT); 489 | prev->next = ptr->next; 490 | ptr = ptr->next; 491 | free(tmptr); 492 | ++nfree; 493 | --nrecord; 494 | } 495 | else { 496 | prev = ptr; 497 | ptr = ptr->next; 498 | } 499 | } 500 | 501 | return (nfree); 502 | } 503 | 504 | void 505 | ic_db_make(int rebuild) { 506 | if (rebuild) 507 | ic_db_cleanup(); 508 | else if (Proc_db != NULL) 509 | return; 510 | 511 | Proc_db = xmalloc(sizeof(proc_db)); 512 | 513 | return; 514 | } 515 | 516 | int 517 | ic_db_nrecord(void) { 518 | return (nrecord); 519 | } 520 | 521 | proc_db * 522 | ic_db_insert(ic_data *dg, int masterfd) { 523 | proc_db *new, *tmptr; 524 | ic_db_lock(); 525 | new = ic_db_make_list(); 526 | new->client = dg->iph.ip_src; 527 | new->local = dg->iph.ip_dst; 528 | new->fd = masterfd; 529 | new->id = dg->icmph.id; 530 | new->create = time(NULL); 531 | new->last = time(NULL); 532 | strcpy(new->clientname, inet_ntoa(dg->iph.ip_src)); 533 | 534 | tmptr = Proc_db->next; 535 | Proc_db->next = new; 536 | new->next = tmptr; 537 | 538 | ic_plog(SDEB, "(ic_db_insert) add entry pid %d", new->id); 539 | ++nrecord; 540 | ic_db_unlock(); 541 | return (new); 542 | } 543 | 544 | proc_db * 545 | ic_db_remove(ic_data *dg) { 546 | proc_db *ptr, *prev; 547 | ic_db_lock(); 548 | prev = Proc_db; 549 | for (ptr = Proc_db->next; ptr != NULL; ptr = ptr->next) { 550 | if (ptr->client.s_addr == dg->iph.ip_src.s_addr && 551 | ptr->id == dg->icmph.id) { 552 | prev->next = ptr->next; 553 | free(ptr); 554 | --nrecord; 555 | break; 556 | } 557 | prev = ptr; 558 | } 559 | 560 | ic_db_unlock(); 561 | return (NULL); 562 | } 563 | 564 | proc_db * 565 | ic_db_find(ic_data *dg, int flag) { 566 | proc_db *ptr; 567 | 568 | if (Proc_db->next == NULL) 569 | return (NULL); 570 | 571 | for (ptr = Proc_db->next; ptr != NULL; ptr = ptr->next) { 572 | if (ptr->client.s_addr == dg->iph.ip_src.s_addr && 573 | ptr->id == dg->icmph.id) { 574 | if (flag & IC_DB_REMOVE) 575 | /* need to improve for performance */ 576 | return (ic_db_remove(dg)); 577 | else { 578 | if (flag & IC_DB_UPDATE) { 579 | ic_db_lock(); 580 | ptr->last = time(NULL); 581 | ic_db_unlock(); 582 | } 583 | return (ptr); 584 | } 585 | } 586 | } 587 | 588 | return (NULL); 589 | } 590 | 591 | proc_db * 592 | ic_db_find_pid(pid_t shelldrv_pid) { 593 | proc_db *ptr; 594 | 595 | if (Proc_db->next == NULL) 596 | return (NULL); 597 | 598 | for (ptr = Proc_db->next; ptr != NULL; ptr = ptr->next) { 599 | if (ptr->shelldrv == shelldrv_pid) 600 | return (ptr); 601 | } 602 | 603 | return (NULL); 604 | } 605 | 606 | 607 | /*------------------------------------------------------------------------- 608 | * shell driver 609 | * 610 | *------------------------------------------------------------------------- 611 | */ 612 | 613 | /* 614 | * ic_shell_driver has to terminate real shell, so that sends SIGTERM to it 615 | * when SIGINT is sent me by the parent. 616 | */ 617 | 618 | static char *pdrv = "ic_shell_driver"; 619 | static char *psh = "shell"; 620 | 621 | static pid_t ic_shelldrv_sigint = 1; /* to terminate myself */ 622 | static pid_t ic_shelldrv_shell = 0; /* real shell's pid */ 623 | 624 | void 625 | ic_shelldrv_kill_child(void) { 626 | if (ic_shelldrv_shell == 0) 627 | return; 628 | ic_kill(pdrv, ic_shelldrv_shell, SIGTERM); 629 | ic_plog(SDEB, "(%s) sent signal to shell (%d)", pdrv, ic_shelldrv_shell); 630 | 631 | return; 632 | } 633 | 634 | void 635 | ic_shelldrv_set_sigint(int signo) { 636 | ic_shelldrv_sigint = 0; 637 | return; 638 | } 639 | 640 | void 641 | ic_shelldrv_catch_sigint(void) { 642 | struct sigaction act, oact; 643 | 644 | act.sa_handler = ic_shelldrv_set_sigint; 645 | sigemptyset(&act.sa_mask); 646 | act.sa_flags = 0; 647 | 648 | if (sigaction(SIGINT, &act, &oact) < 0) 649 | ic_plog(SDEB, "(%s) can not set signal handler", pdrv); 650 | 651 | return; 652 | } 653 | 654 | void 655 | ic_shelldrv_chld_stat(int signo) { 656 | pid_t pid; 657 | int status; 658 | 659 | while((pid = waitpid(-1, &status, WNOHANG)) > 0) { 660 | ic_plog(SDEB, "(%s) child process %d terminated", pdrv, pid); 661 | } 662 | 663 | if (pid == ic_shelldrv_shell) 664 | ic_shelldrv_shell = 0; 665 | 666 | /* exit main loop in ic_shell_driver() */ 667 | ic_shelldrv_set_sigint(0); 668 | 669 | return; 670 | } 671 | 672 | void 673 | ic_shelldrv_catch_sigchld(void) { 674 | struct sigaction act, oact; 675 | 676 | act.sa_handler = ic_shelldrv_chld_stat; 677 | sigemptyset(&act.sa_mask); 678 | act.sa_flags = 0; 679 | 680 | if (sigaction(SIGCHLD, &act, &oact) < 0) 681 | ic_plog(SDEB, "(%s) can not set signal handler", pdrv); 682 | 683 | return; 684 | } 685 | 686 | /* 687 | * ic_shell_driver main 688 | */ 689 | 690 | void 691 | ic_set_icmp_echoreply(ic_data *pic, proc_db *pproc, u_char *ibuf, ssize_t sz) { 692 | u_short pid = pproc->id; 693 | u_short len = sz; 694 | 695 | ic_set_data(pic, IC_REPLY, IC_NORMAL, len, ibuf, sz); 696 | ic_set_header(pic, ICMP_ECHOREPLY, 0, pid, IC_TAG); 697 | 698 | return; 699 | } 700 | 701 | int 702 | ic_responser(bufset *nbuf, proc_db *pproc) { 703 | ic_data dg; 704 | icmp_echo *picmph = &(dg.icmph); 705 | SA_IN addr; 706 | 707 | addr.sin_family = AF_INET; 708 | addr.sin_addr.s_addr = pproc->client.s_addr; 709 | 710 | while (nbuf->len > 0) { 711 | int iclen, send, retry; 712 | if (nbuf->len > IC_REALPAYLOAD) { 713 | iclen = IC_REALPAYLOAD; 714 | nbuf->len -= IC_REALPAYLOAD; 715 | } 716 | else { 717 | iclen = nbuf->len; 718 | nbuf->len = 0; 719 | } 720 | memset(&dg, 0, sizeof(dg)); 721 | ic_set_icmp_echoreply(&dg, pproc, nbuf->buf, iclen); 722 | for (retry = 5; retry > 0; --retry) { 723 | send = sendto(sockout, (icmp_echo *)picmph, IC_DATASIZE, 0, (SA *)&addr, sizeof(addr)); 724 | if (send < 0) { 725 | if (errno == ENOBUFS) 726 | continue; 727 | ic_plog(SINF, "(%s) unrecoverable error occured (%s)", pdrv, strerror(errno)); 728 | return (-1); 729 | } 730 | else if (send == IC_DATASIZE) 731 | break; 732 | } 733 | } 734 | 735 | return (0); 736 | } 737 | 738 | int 739 | ic_write_terminal(int shmaster, bufset *nbuf, pid_t shell) { 740 | switch (nbuf->buf[0]) { 741 | case IAC: 742 | switch (nbuf->buf[1]) { 743 | #ifdef SOLARIS 744 | case IP: 745 | (void) ioctl(shmaster, TIOCSIGNAL, SIGINT); 746 | break; 747 | case SUSP: 748 | (void) ioctl(shmaster, TIOCSIGNAL, SIGTSTP); 749 | break; 750 | case ABORT: 751 | (void) ioctl(shmaster, TIOCSIGNAL, SIGQUIT); 752 | break; 753 | default: 754 | break; 755 | } 756 | #else 757 | case IP: 758 | (void) ioctl(shmaster, TIOCSIG, (char *)SIGINT); 759 | break; 760 | case SUSP: 761 | (void) ioctl(shmaster, TIOCSIG, (char *)SIGTSTP); 762 | break; 763 | case ABORT: 764 | (void) ioctl(shmaster, TIOCSIG, (char *)SIGQUIT); 765 | break; 766 | default: 767 | break; 768 | } 769 | #endif 770 | break; 771 | default: 772 | xwrite(shmaster, nbuf->buf, nbuf->len); 773 | break; 774 | } 775 | nbuf->len = 0; 776 | 777 | return (0); 778 | } 779 | 780 | int 781 | ic_read_tty(int fd, bufset *nbuf) { 782 | int retry; 783 | int cc; 784 | u_char tempbuff[BUFSIZ]; 785 | 786 | for (retry = 5; retry > 0; --retry) { 787 | cc = read(fd, tempbuff, nbuf->bufsz); 788 | if (cc < 0) 789 | if (errno == EINTR) 790 | continue; 791 | else 792 | return (0); 793 | else 794 | break; 795 | } 796 | 797 | if (cc > 0) { 798 | if ((nbuf->len + cc) > nbuf->bufsz) { 799 | nbuf->bufsz *= 2; 800 | nbuf->buf = xrealloc(nbuf->buf, nbuf->bufsz); 801 | ic_plog(SDEB, "(%s) expand bufset (%d)", pdrv, nbuf->bufsz); 802 | } 803 | memcpy(nbuf->buf + nbuf->len, tempbuff, cc); 804 | nbuf->len += cc; 805 | } 806 | 807 | return (cc); 808 | } 809 | 810 | 811 | void 812 | ic_make_buf(bufset *term, bufset *net) { 813 | term->bufsz = net->bufsz = IC_REALPAYLOAD; 814 | term->len = net->len = 0; 815 | term->buf = xmalloc(term->bufsz); 816 | net->buf = xmalloc(net->bufsz); 817 | return; 818 | } 819 | 820 | char * 821 | ic_login_path() { 822 | #ifdef SOLARIS 823 | static char *login = "/bin/login"; 824 | #else 825 | static char *login = "/usr/bin/login"; 826 | #endif 827 | return (login); 828 | } 829 | 830 | #ifdef SOLARIS 831 | void 832 | ic_make_utmpx(char *pts) { 833 | struct utmpx ut; 834 | 835 | (void) memset((char *)&ut, 0, sizeof(ut)); 836 | (void) strncpy(ut.ut_user, ".telnet", sizeof (ut.ut_user)); 837 | (void) strncpy(ut.ut_line, pts, sizeof(ut.ut_line)); 838 | ut.ut_pid = getpid(); 839 | ut.ut_id[0] = 't'; 840 | ut.ut_id[1] = (char)SC_WILDC; 841 | ut.ut_id[2] = (char)SC_WILDC; 842 | ut.ut_id[3] = (char)SC_WILDC; 843 | ut.ut_type = LOGIN_PROCESS; 844 | ut.ut_exit.e_termination = 0; 845 | ut.ut_exit.e_exit = 0; 846 | (void) time(&ut.ut_tv.tv_sec); 847 | if (makeutx(&ut) == NULL) 848 | ic_plog(SDEB, "(%s) makeutx fail", pdrv); 849 | 850 | return; 851 | } 852 | #endif 853 | 854 | void 855 | ic_shell_driver(int master, char *pts, char **envp, struct termios tt, struct winsize ws, proc_db proc) { 856 | const char *login = ic_login_path(); 857 | int slave, shmaster, maxfd; 858 | int on = 1; 859 | struct termios rawtt; 860 | pid_t shellpid; 861 | char pts_shell[64]; /* save pts name, /dev/ptyXY */ 862 | bufset termbuf, netbuf; 863 | fd_set rfd, wfd; 864 | 865 | /* 866 | * get `pts' to communicate between icmpshd and ic_shell_driver, 867 | * and close master 868 | */ 869 | if ((slave = ptys_open(master, pts)) < 0) { 870 | ic_plog(SDEB, "(%s) ptys_open failure", pdrv); 871 | return; 872 | } 873 | rawtt = tt; 874 | cfmakeraw(&rawtt); 875 | if (tcsetattr(slave, TCSANOW, &rawtt) < 0) 876 | ic_plog(SDEB, "(%s) tcsetattr failure (%s)", pdrv, strerror(errno)); 877 | 878 | if (setsid() < 0) { 879 | ic_plog(SDEB, "(%s) setsid failure", pdrv); 880 | return; 881 | } 882 | 883 | if ((shmaster = ptym_open(pts_shell)) < 0) { 884 | ic_plog(SDEB, "(%s) ptym_open failure", pdrv); 885 | return; 886 | } 887 | (void) ioctl(shmaster, FIONBIO, (char *)&on); 888 | 889 | if ((shellpid = xfork()) == 0) { 890 | /* start real shell */ 891 | int shslave; 892 | if (setsid() < 0) 893 | return; 894 | if ((shslave = ptys_open(shmaster, pts_shell)) < 0) 895 | return; 896 | #ifndef SOLARIS 897 | /* ioctl(tty) not needed on SVR4 898 | * slave becomes control terminal when process opens ptys 899 | */ 900 | if (ioctl(shslave, TIOCSCTTY, (char *)NULL) < 0) 901 | ic_plog(SDEB, "(%s) ioctl(tty) failure (%s)", psh, strerror(errno)); 902 | #endif 903 | tt.c_lflag |= ECHO; 904 | if (tcsetattr(shslave, TCSANOW, &tt) < 0) 905 | return; 906 | if (ioctl(shslave, TIOCSWINSZ, &ws) < 0) 907 | return; 908 | ic_plog(SDEB, "(%s) forked(%d)", psh, getpid()); 909 | dup2(shslave, 0); 910 | dup2(shslave, 1); 911 | dup2(shslave, 2); 912 | #ifdef SOLARIS 913 | ic_make_utmpx(pts_shell+6); 914 | execl(login, "login", "-p", "-h", proc.clientname, "-d", pts_shell, "--", getenv("USER"), 0); 915 | #else 916 | execle(login, "login", "-h", proc.clientname, "-p", (char *)NULL, envp); 917 | #endif 918 | ic_plog(SDEB, "(%s) fork login failure", psh); 919 | return; 920 | } 921 | else if (shellpid < 0) { 922 | ic_plog(SDEB, "(%s) fork failure", pdrv); 923 | return; 924 | } 925 | 926 | /*---------------------------------------------------- 927 | * ic_shell_driver main loop 928 | *---------------------------------------------------- 929 | */ 930 | 931 | ic_shelldrv_shell = shellpid; 932 | ic_shelldrv_catch_sigint(); 933 | ic_shelldrv_catch_sigchld(); 934 | 935 | ic_make_buf(&termbuf, &netbuf); 936 | MAXFD3(maxfd, shmaster, slave, sockout); 937 | FD_ZERO(&rfd); 938 | FD_ZERO(&wfd); 939 | 940 | while (ic_shelldrv_sigint) { 941 | int nfd; 942 | FD_ZERO(&wfd); 943 | if (termbuf.len) 944 | FD_SET(shmaster, &wfd); 945 | if (netbuf.len) 946 | FD_SET(sockout, &wfd); 947 | FD_SET(shmaster, &rfd); 948 | FD_SET(slave, &rfd); 949 | nfd = select(maxfd + 1, &rfd, &wfd, NULL, NULL); 950 | if (nfd < 0) { 951 | if (errno == EINTR) 952 | continue; 953 | ic_plog(SDEB, "(%s) select failure", pdrv); 954 | break; 955 | } 956 | /* 957 | * response to client (write to network) 958 | */ 959 | if (nfd > 0 && netbuf.len > 0 && FD_ISSET(sockout, &wfd)) { 960 | (void) ic_responser(&netbuf, &proc); 961 | } 962 | /* 963 | * write to real-shell 964 | */ 965 | if (nfd > 0 && termbuf.len > 0 && FD_ISSET(shmaster, &wfd)) { 966 | (void) ic_write_terminal(shmaster, &termbuf, shellpid); 967 | } 968 | /* 969 | * read from shell 970 | */ 971 | if (nfd > 0 && FD_ISSET(shmaster, &rfd)) { 972 | (void) ic_read_tty(shmaster, &netbuf); 973 | } 974 | /* 975 | * read from network and store in buffer 976 | */ 977 | if (nfd > 0 && FD_ISSET(slave, &rfd)) { 978 | (void) ic_read_tty(slave, &termbuf); 979 | } 980 | } 981 | 982 | ic_shelldrv_kill_child(); 983 | 984 | ic_plog(SDEB, "(%s) exit", pdrv); 985 | exit (0); 986 | } 987 | 988 | 989 | /*------------------------------------------------------------------------- 990 | * request handler 991 | * ic_reply() common interface for ic_req_start & ic_req_quit 992 | * ic_req_start() startup procedure 993 | * ic_req_quit() remove child process and clean up database 994 | *------------------------------------------------------------------------- 995 | */ 996 | 997 | int 998 | ic_reply(u_char code, proc_db *proc) { 999 | int send; 1000 | ic_data dg; 1001 | icmp_echo *picmph = &(dg.icmph); 1002 | SA_IN dst; 1003 | 1004 | memset(&dg, 0, sizeof(dg)); 1005 | ic_set_data(&dg, code, IC_NORMAL, 0, NULL, 0); 1006 | ic_set_header(&dg, ICMP_ECHOREPLY, 0, proc->id, IC_TAG); 1007 | 1008 | dst.sin_family = AF_INET; 1009 | dst.sin_addr.s_addr = proc->client.s_addr; 1010 | for (;;) { 1011 | send = sendto(sockout, (icmp_echo *)picmph, IC_DATASIZE, 0, (SA *)&dst, sizeof(dst)); 1012 | if (send == IC_DATASIZE) 1013 | break; 1014 | if (send < 0 && errno == ENOBUFS) { 1015 | continue; 1016 | } 1017 | ic_plog(SDEB, "(ic_reply) sendto() failure"); 1018 | return (-1); 1019 | } 1020 | 1021 | return (0); 1022 | } 1023 | 1024 | 1025 | /* IC_START */ 1026 | 1027 | int 1028 | ic_req_start(ic_data *pdg, char **envp, OPT *opt) { 1029 | int master; 1030 | int on = 1; 1031 | char pts[64]; /* save pts name, /dev/ptyXY */ 1032 | proc_db *proc; 1033 | pid_t shelldrv; 1034 | 1035 | if ((master = ptym_open(pts)) < 0) { 1036 | ic_plog(SDEB, "(main) ptym_open failure"); 1037 | return (-1); 1038 | } 1039 | (void) ioctl(master, FIONBIO, (char *)&on); 1040 | 1041 | proc = ic_db_insert(pdg, master); 1042 | 1043 | if ((shelldrv = xfork()) == 0) { 1044 | /* ic_shell_driver start */ 1045 | struct winsize ws; 1046 | ic_get_winsz(&ws, &(pdg->data.ich.opt.nwinsz)); 1047 | ic_shell_driver(master, pts, envp, opt->origtt, ws, *proc); 1048 | } 1049 | else if (shelldrv < 0) { 1050 | ic_db_remove(pdg); 1051 | return (-1); 1052 | } 1053 | 1054 | proc->shelldrv = shelldrv; 1055 | ic_plog(SDEB, "(main) open master (%d) for shelldrv pid (%d)", master, shelldrv); 1056 | ic_reply(IC_START_ACK, proc); 1057 | 1058 | return (0); 1059 | } 1060 | 1061 | 1062 | /* IC_REQ */ 1063 | int 1064 | ic_req_req(ic_data *pdg) { 1065 | u_char *ppay = (u_char *)&(pdg->data.payload[0]) + sizeof(ic_header); 1066 | proc_db *proc; 1067 | 1068 | if ((proc = ic_db_find(pdg, IC_DB_UPDATE)) == NULL) { 1069 | ic_plog(SDEB, "(main) no entry in proc_db"); 1070 | return (-1); 1071 | } 1072 | 1073 | xwrite(proc->fd, ppay, pdg->data.ich.length); 1074 | ic_plog(SDEB, "(main) sent through fd(%d), %d byte", proc->fd, pdg->data.ich.length); 1075 | 1076 | return (0); 1077 | } 1078 | 1079 | 1080 | /* IC_QUIT */ 1081 | int 1082 | ic_req_quit(ic_data *pdg) { 1083 | proc_db *proc; 1084 | 1085 | if ((proc = ic_db_find(pdg, 0)) == NULL) { 1086 | ic_plog(SDEB, "(main) no entry in proc_db"); 1087 | return (-1); 1088 | } 1089 | 1090 | /* 1091 | * terminate ic_shell_driver and its child(shell), see ic_shell_driver() 1092 | * in detail. 1093 | */ 1094 | ic_kill("main", proc->shelldrv, SIGINT); 1095 | ic_reply(IC_QUIT_ACK, proc); 1096 | 1097 | /* 1098 | * remove entry from proc_db 1099 | */ 1100 | if ((proc = ic_db_remove(pdg)) == NULL) 1101 | ic_plog(SDEB, "(main) removed entry"); 1102 | else 1103 | ic_plog(SDEB, "(main) can not remove entry"); 1104 | 1105 | return (0); 1106 | } 1107 | 1108 | 1109 | /*------------------------------------------------------------------------- 1110 | * main 1111 | *------------------------------------------------------------------------- 1112 | */ 1113 | 1114 | /* 1115 | * make new environment 1116 | */ 1117 | void 1118 | ic_env_make(void *envp) { 1119 | extern char **environ; 1120 | int i; 1121 | int envn = 16; 1122 | char **newenvp; 1123 | 1124 | newenvp = xmalloc(envn * sizeof(char *)); 1125 | for (i = 0; environ[i] != NULL; ++i) { 1126 | if (i == envn) { 1127 | envn *= 2; 1128 | newenvp = xrealloc(newenvp, envn * sizeof(char *)); 1129 | } 1130 | newenvp[i] = xstrdup(environ[i]); 1131 | } 1132 | if (getenv("TERM") == NULL) { 1133 | newenvp[i] = xstrdup("TERM=vt100"); 1134 | ++i; 1135 | } 1136 | 1137 | if (i >= envn) 1138 | newenvp = xrealloc(newenvp, (i + 1) * sizeof(char *)); 1139 | newenvp[i] = NULL; 1140 | *((char **)envp) = (char *)newenvp; 1141 | 1142 | return; 1143 | } 1144 | 1145 | 1146 | /* 1147 | * finger out whether incoming packet is icmpsh's format or not, 1148 | * then return with value "1", which means true ("0" as opposite to "1") 1149 | */ 1150 | int 1151 | ic_is_icmpsh_server(ic_data *pdg) { 1152 | if (pdg->iph.ip_hl != IC_IPHLWRS) 1153 | return (0); 1154 | 1155 | if (pdg->icmph.seq == IC_TAG && 1156 | (pdg->icmph.type == ICMP_ECHO || 1157 | pdg->icmph.type == ICMP_ECHOREPLY)) 1158 | ic_plog(SDEB, "(main) accept icmpsh packet"); 1159 | else 1160 | return (0); 1161 | 1162 | ic_plog(SDEB, "(main) src(%s), ", inet_ntoa(pdg->iph.ip_src)); 1163 | ic_plog(SDEB, "(main) dst(%s), ", inet_ntoa(pdg->iph.ip_dst)); 1164 | ic_plog(SDEB, "(main) type(%d), ", pdg->icmph.type); 1165 | ic_plog(SDEB, "(main) code(%d), ", pdg->icmph.code); 1166 | ic_plog(SDEB, "(main) id(%d), ", pdg->icmph.id); 1167 | ic_plog(SDEB, "(main) seq(%d), ", pdg->icmph.seq); 1168 | ic_plog(SDEB, "(main) type(%d)", pdg->data.ich.type); 1169 | 1170 | return (1); 1171 | } 1172 | 1173 | /* 1174 | * open and configure socket 1175 | */ 1176 | int 1177 | ic_init_server(OPT *opt) { 1178 | int on = 1; 1179 | 1180 | if ((sockin = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) { 1181 | ic_plog(SDEB, "(main) socket failure in(%d)", sockin); 1182 | return (-1); 1183 | } 1184 | if ((sockout = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) { 1185 | ic_plog(SDEB, "(main) socket failure out(%d)", sockout); 1186 | return (-1); 1187 | } 1188 | 1189 | if (ioctl(sockout, FIONBIO, (char *)&on) == -1) { 1190 | ic_plog(SDEB, "(main) ioctl error sockout (%s)", strerror(errno)); 1191 | return (-1); 1192 | } 1193 | if (opt->src) { 1194 | if (bind(sockin, opt->src, opt->srclen) != 0) { 1195 | ic_plog(SDEB, "(main) bind error (%s)", strerror(errno)); 1196 | return (-1); 1197 | } 1198 | } 1199 | 1200 | return (0); 1201 | } 1202 | 1203 | 1204 | int 1205 | main(int argc, char **argv) { 1206 | OPT *opt; /* command option */ 1207 | char **envp; 1208 | 1209 | opt = ic_option(argc, argv); 1210 | openlog(program, LOG_PID, opt->fac); 1211 | 1212 | /* preparation */ 1213 | if (debug) 1214 | ic_catch_status(); 1215 | else 1216 | ic_go_daemon(opt); 1217 | 1218 | ic_put_pidfile(opt); 1219 | ic_db_make(0); 1220 | ic_env_make(&envp); 1221 | 1222 | /* socket */ 1223 | if (ic_init_server(opt) < 0) 1224 | exit (1); 1225 | 1226 | /* 1227 | * main loop 1228 | */ 1229 | ic_plog(SINF, "(main) starting up"); 1230 | 1231 | for(;;) { 1232 | int nfd; 1233 | ic_data dg; /* ip datagram */ 1234 | ssize_t n; 1235 | SA_IN src; 1236 | socklen_t srclen; 1237 | 1238 | ic_plog(SDEB, "(main) waiting(pid:%d)", getpid()); 1239 | 1240 | if ((nfd = ic_select(sockin, opt->timeout)) == 0) { 1241 | /* timeout */ 1242 | ic_plog(SINF, "(main) proc database -> %d", ic_db_nrecord()); 1243 | ic_db_cleanup_old(time(NULL), opt->timeout); 1244 | continue; 1245 | } 1246 | memset(&dg, 0, sizeof(dg)); 1247 | n = recvfrom(sockin, (ic_data *)&dg, sizeof(dg), 0, (SA *)&src, &srclen); 1248 | if (n < 0) { 1249 | if (errno == EINTR) 1250 | continue; 1251 | else { 1252 | ic_plog(SDEB, "(main) error occued while reading, quit immediately"); 1253 | exit (1); 1254 | } 1255 | } 1256 | else if (n == 0) { 1257 | ic_plog(SDEB, "(main) no data read"); 1258 | continue; 1259 | } 1260 | else if (n != IC_IPSIZE) { 1261 | ic_plog(SDEB, "(main) mismatch packet size"); 1262 | continue; 1263 | } 1264 | 1265 | /* Is it icmpsh's packet ?? */ 1266 | ic_plog(SDEB, "(main) received packet (%d)", n); 1267 | ic_recv_ntohs(&dg); 1268 | if (ic_is_icmpsh_server(&dg) == 0) 1269 | continue; 1270 | 1271 | /* execute command */ 1272 | switch (dg.data.ich.type) { 1273 | case (IC_START): 1274 | ic_plog(SDEB, "(main) req: IC_START"); 1275 | (void) ic_req_start(&dg, envp, opt); 1276 | break; 1277 | case (IC_REQ): 1278 | ic_plog(SDEB, "(main) req: IC_REQ"); 1279 | (void) ic_req_req(&dg); 1280 | break; 1281 | case (IC_QUIT): 1282 | ic_plog(SDEB, "(main) req: IC_QUIT"); 1283 | (void) ic_req_quit(&dg); 1284 | break; 1285 | default: 1286 | ic_plog(SDEB, "(main) request not implemented"); 1287 | } 1288 | } 1289 | 1290 | exit(0); 1291 | } 1292 | 1293 | -------------------------------------------------------------------------------- /openpty.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006 Tsuyoshi SAKAMOTO , 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 19 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 20 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 23 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 26 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 27 | * DAMAGE. 28 | */ 29 | 30 | 31 | 32 | /******************************************** 33 | * include file 34 | ******************************************** 35 | */ 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #ifdef SOLARIS 45 | #include 46 | #include 47 | #include 48 | #include 49 | #else /* BSD & Mac */ 50 | #include 51 | #endif 52 | 53 | 54 | /******************************************** 55 | * macro 56 | ******************************************** 57 | */ 58 | 59 | 60 | /******************************************** 61 | * type definition 62 | ******************************************** 63 | */ 64 | 65 | 66 | /******************************************** 67 | * global variable 68 | ******************************************** 69 | */ 70 | 71 | 72 | /******************************************** 73 | * prototype 74 | ******************************************** 75 | */ 76 | /* public */ 77 | int ptym_open(char *); 78 | int ptys_open(int, char *); 79 | 80 | 81 | /******************************************** 82 | * open master and slave 83 | ******************************************** 84 | */ 85 | #ifdef SOLARIS 86 | int 87 | ptym_open(char *pts) { 88 | char ptym[] = "/dev/ptmx"; 89 | char *p; 90 | int master; 91 | 92 | if (pts == NULL) 93 | return (-1); 94 | 95 | if ((master = open(ptym, O_RDWR)) < 0) 96 | return (-1); 97 | 98 | if (grantpt(master) < 0) 99 | goto ptym_open_error; 100 | 101 | if (unlockpt(master) < 0) 102 | goto ptym_open_error; 103 | 104 | if ((p = ptsname(master)) == NULL) 105 | goto ptym_open_error; 106 | 107 | strcpy(pts, p); 108 | return (master); 109 | 110 | ptym_open_error: 111 | close(master); 112 | return (-1); 113 | } 114 | 115 | int 116 | ptys_open(int master, char *pts_name) { 117 | int slave; 118 | 119 | if ((slave = open(pts_name, O_RDWR)) < 0) { 120 | close(master); 121 | return (-1); 122 | } 123 | 124 | if (ioctl(slave, I_PUSH, "ptem") < 0) 125 | goto ptys_open_error; 126 | 127 | if (ioctl(slave, I_PUSH, "ldterm") < 0) 128 | goto ptys_open_error; 129 | 130 | if (ioctl(slave, I_PUSH, "ttcompat") < 0) 131 | goto ptys_open_error; 132 | 133 | return (slave); 134 | 135 | ptys_open_error: 136 | close(master); 137 | close(slave); 138 | return (-1); 139 | } 140 | #else /* BSD & Mac */ 141 | int 142 | ptym_open(char *pts_name) { 143 | int master; 144 | char *ptr1, *ptr2; 145 | 146 | if (pts_name == NULL) 147 | return (-1); 148 | 149 | strcpy(pts_name, "/dev/ptyXY"); 150 | for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1 != 0; ++ptr1) { 151 | pts_name[8] = *ptr1; 152 | for (ptr2 = "0123456789abcdef"; *ptr2 != 0; ++ptr2) { 153 | pts_name[9] = *ptr2; 154 | if ((master = open(pts_name, O_RDWR)) < 0) { 155 | if (errno == ENOENT) 156 | return (-1); 157 | else 158 | continue; 159 | } 160 | pts_name[5] = 't'; 161 | return (master); 162 | } 163 | } 164 | 165 | return (-1); 166 | } 167 | 168 | int 169 | ptys_open(int master, char *pts_name) { 170 | struct group *grptr; 171 | int gid, slave; 172 | 173 | if (master < 0 || pts_name == NULL) 174 | return (-1); 175 | 176 | if ((grptr = getgrnam("tty")) != NULL) 177 | gid = grptr->gr_gid; 178 | else 179 | gid = -1; 180 | 181 | chown(pts_name, getuid(), gid); 182 | chmod(pts_name, S_IRUSR|S_IWUSR|S_IWGRP); 183 | 184 | if ((slave = open(pts_name, O_RDWR)) < 0) { 185 | close(master); 186 | return (-1); 187 | } 188 | 189 | return (slave); 190 | } 191 | #endif 192 | 193 | /* end of source */ 194 | -------------------------------------------------------------------------------- /utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006 Tsuyoshi SAKAMOTO , 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 19 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 20 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 23 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 26 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 27 | * DAMAGE. 28 | */ 29 | 30 | 31 | /******************************************** 32 | * include file 33 | ******************************************** 34 | */ 35 | #include "icmpsh.h" 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include 43 | 44 | #include 45 | #include 46 | 47 | #include 48 | #include 49 | #include 50 | 51 | #include 52 | #include 53 | #include 54 | 55 | #include 56 | 57 | #include 58 | #include 59 | 60 | 61 | /******************************************** 62 | * macro 63 | ******************************************** 64 | */ 65 | 66 | 67 | /******************************************** 68 | * type definition 69 | ******************************************** 70 | */ 71 | 72 | 73 | /******************************************** 74 | * global variable 75 | ******************************************** 76 | */ 77 | extern int debug; 78 | 79 | 80 | /* syslog */ 81 | const int level[] = { 82 | LOG_EMERG, 83 | LOG_ALERT, 84 | LOG_CRIT, 85 | LOG_ERR, 86 | LOG_WARNING, 87 | LOG_NOTICE, 88 | LOG_INFO, 89 | LOG_DEBUG, 90 | 0 /* syslog off */ 91 | }; 92 | 93 | 94 | /******************************************** 95 | * proto type 96 | ******************************************** 97 | */ 98 | 99 | /* public */ 100 | 101 | #ifdef SOLARIS 102 | void cfmakeraw(struct termios *); 103 | #endif 104 | 105 | int ic_select(int, long); 106 | void ic_plog(int, const char *, ...); 107 | void ic_log(const char *, ...); 108 | void ic_recv_ntohs(ic_data *); 109 | void ic_set_termios(net_termios *, struct termios *); 110 | void ic_set_winsz(net_winsz *, struct winsize *); 111 | void ic_get_termios(struct termios *, net_termios *); 112 | void ic_get_winsz(struct winsize *, net_winsz *); 113 | void ic_set_data(ic_data *, u_char, u_char, u_short, u_char *, int); 114 | void ic_set_header(ic_data *, u_char, u_char, u_short, u_short); 115 | static void ic_convert_data(ic_data *); 116 | static void ic_convert_header(ic_data *); 117 | 118 | ssize_t xread(int, void *, size_t); 119 | ssize_t xwrite(int, void *, size_t); 120 | 121 | void vsys_err(int, const char *, ...); 122 | void vsys(int, const char *, ...); 123 | 124 | u_short xchecksum(u_short *, int); 125 | 126 | pid_t xfork(void); 127 | 128 | void *xmalloc(size_t); 129 | void *xrealloc(void *, size_t); 130 | 131 | char *xstrdup(char *); 132 | 133 | 134 | /* local */ 135 | static int xselect(int, fd_set *, fd_set *, fd_set *, struct timeval *); 136 | 137 | 138 | /*============================================================================ 139 | * program section 140 | *============================================================================ 141 | */ 142 | 143 | #ifdef SOLARIS 144 | /*------------------------------------------------------------------------- 145 | * cfmakeraw for Solaris 146 | * 147 | *------------------------------------------------------------------------- 148 | */ 149 | void 150 | cfmakeraw(struct termios *t) 151 | { 152 | memset(t, 0, sizeof(struct termios)); 153 | 154 | t->c_iflag |= IGNBRK; 155 | t->c_cflag |= CS8|CREAD; 156 | t->c_cc[VMIN] = 1; 157 | t->c_cc[VTIME] = 0; 158 | 159 | return; 160 | } 161 | #endif 162 | 163 | /*------------------------------------------------------------------------- 164 | * termios and window size 165 | * 166 | *------------------------------------------------------------------------- 167 | */ 168 | void 169 | ic_set_termios(net_termios *pn, struct termios *pt) { 170 | int i; 171 | pn->c_iflag = htonl(pt->c_iflag); 172 | pn->c_oflag = htonl(pt->c_oflag); 173 | pn->c_cflag = htonl(pt->c_cflag); 174 | pn->c_lflag = htonl(pt->c_lflag); 175 | #ifndef SOLARIS 176 | pn->c_ispeed = htonl(pt->c_ispeed); 177 | pn->c_ospeed = htonl(pt->c_ospeed); 178 | #endif 179 | for (i = 0; i < NCCS; ++i) { 180 | pn->c_cc[i] = pt->c_cc[i]; 181 | } 182 | return; 183 | } 184 | 185 | void 186 | ic_set_winsz(net_winsz *pn, struct winsize *pt) { 187 | pn->ws_row = htons(pt->ws_row); 188 | pn->ws_col = htons(pt->ws_col); 189 | pn->ws_xpixel = htons(pt->ws_xpixel); 190 | pn->ws_ypixel = htons(pt->ws_ypixel); 191 | return; 192 | } 193 | 194 | void 195 | ic_get_termios(struct termios *pt, net_termios *pn) { 196 | int i; 197 | pt->c_iflag = ntohl(pn->c_iflag); 198 | pt->c_oflag = ntohl(pn->c_oflag); 199 | pt->c_cflag = ntohl(pn->c_cflag); 200 | pt->c_lflag = ntohl(pn->c_lflag); 201 | #ifndef SOLARIS 202 | pt->c_ispeed = ntohl(pn->c_ispeed); 203 | pt->c_ospeed = ntohl(pn->c_ospeed); 204 | #endif 205 | for (i = 0; i < NCCS; ++i) { 206 | pt->c_cc[i] = pn->c_cc[i]; 207 | } 208 | return; 209 | } 210 | 211 | void 212 | ic_get_winsz(struct winsize *pt, net_winsz *pn) { 213 | pt->ws_row = ntohs(pn->ws_row); 214 | pt->ws_col = ntohs(pn->ws_col); 215 | pt->ws_xpixel = ntohs(pn->ws_xpixel); 216 | pt->ws_ypixel = ntohs(pn->ws_ypixel); 217 | return; 218 | } 219 | 220 | 221 | /*------------------------------------------------------------------------- 222 | * debug log handler 223 | * 224 | *------------------------------------------------------------------------- 225 | */ 226 | void 227 | ic_plog(int lvl, const char *format, ...) { 228 | va_list ap; 229 | va_start(ap, format); 230 | 231 | if (debug) { 232 | vfprintf(stderr, format, ap); 233 | fprintf(stderr, "\n"); 234 | } 235 | else { 236 | if (level[lvl]) 237 | vsyslog(level[lvl], format, ap); 238 | } 239 | 240 | va_end(ap); 241 | 242 | return; 243 | } 244 | 245 | void 246 | ic_log(const char *format, ...) { 247 | va_list ap; 248 | va_start(ap, format); 249 | 250 | if (debug) { 251 | vfprintf(stderr, format, ap); 252 | fprintf(stderr, "\n"); 253 | } 254 | 255 | va_end(ap); 256 | 257 | return; 258 | } 259 | 260 | /*------------------------------------------------------------------------- 261 | * convert net byte order to host byte order 262 | * 263 | *------------------------------------------------------------------------- 264 | */ 265 | void 266 | ic_recv_ntohs(ic_data *pic) { 267 | char *p; 268 | struct ip *piph; 269 | icmp_echo *picmph; 270 | ic_header *pich; 271 | 272 | p = (char *)pic; 273 | piph = (struct ip *)p; 274 | picmph = (icmp_echo *)(p + (IC_IPHLWRS * 4)); 275 | pich = (ic_header *)(p + (IC_IPHLWRS * 4) + sizeof(icmp_echo)); 276 | 277 | ic_convert_header(pic); 278 | ic_convert_data(pic); 279 | 280 | return; 281 | } 282 | 283 | 284 | /*------------------------------------------------------------------------- 285 | * select with error check 286 | * arg: the same as select()'s 287 | * ret: >=0(success), -1(failure) 288 | *------------------------------------------------------------------------- 289 | */ 290 | int 291 | xselect(int nfd, fd_set *rfd, fd_set *wfd, fd_set *ofd, struct timeval *pt) { 292 | int n; 293 | 294 | for (;;) { 295 | if ((n = select(nfd, rfd, wfd, ofd, pt)) < 0) { 296 | if (errno == EINTR) 297 | continue; 298 | } 299 | else 300 | break; 301 | } 302 | 303 | return (n); 304 | } 305 | 306 | /* 307 | * common select interface for icmsh 308 | */ 309 | int 310 | ic_select(int nfd, long timeout) { 311 | int n; 312 | struct timeval tv, *ptv; 313 | fd_set rfd; 314 | 315 | memset(&rfd, 0, sizeof(rfd)); 316 | tv.tv_sec = timeout; 317 | tv.tv_usec = 0; 318 | 319 | ptv = &tv; 320 | for (;;) { 321 | FD_ZERO(&rfd); 322 | FD_SET(nfd, &rfd); 323 | if ((n = xselect(nfd + 1, &rfd, NULL, NULL, ptv)) < 0) { 324 | break; 325 | } 326 | else if (n == 0) { 327 | break; 328 | } 329 | if (FD_ISSET(nfd, &rfd)) 330 | break; 331 | } 332 | 333 | return (n); 334 | } 335 | 336 | 337 | /*------------------------------------------------------------------------- 338 | * ic_data common interface 339 | * 340 | * 341 | *------------------------------------------------------------------------- 342 | */ 343 | void 344 | ic_set_data(ic_data *p, u_char type, u_char flag, u_short length, u_char *buf, int bufsz) { 345 | u_char *ppay = (u_char *)&(p->data.payload[0]) + sizeof(ic_header); 346 | p->data.ich.type = type; 347 | p->data.ich.flag = flag; 348 | p->data.ich.length = htons(length); 349 | if (buf) 350 | strncpy((char *)ppay, (char *)buf, bufsz); 351 | return; 352 | } 353 | 354 | void 355 | ic_set_header(ic_data *p, u_char type, u_char code, u_short id, u_short seq) { 356 | p->icmph.type = type; 357 | p->icmph.code = code; 358 | p->icmph.id = htons(id); 359 | p->icmph.seq = htons(seq); 360 | p->icmph.cksum = xchecksum((u_short *)&(p->icmph), IC_DATASIZE); 361 | return; 362 | } 363 | 364 | void 365 | ic_convert_data(ic_data *p) { 366 | p->data.ich.length = ntohs(p->data.ich.length); 367 | return; 368 | } 369 | 370 | void 371 | ic_convert_header(ic_data *p) { 372 | p->icmph.id = ntohs(p->icmph.id); 373 | p->icmph.seq = ntohs(p->icmph.seq); 374 | return; 375 | } 376 | 377 | 378 | /*------------------------------------------------------------------------- 379 | * send / wait signal 380 | * 381 | *------------------------------------------------------------------------- 382 | */ 383 | int 384 | ic_kill(char *proc, pid_t p, int sig) { 385 | int rc; 386 | if ((rc = kill(p, sig)) != 0) 387 | ic_plog(SINF, "(%s) kill failure (%s)", proc, strerror(errno)); 388 | 389 | return (rc); 390 | } 391 | 392 | pid_t 393 | ic_waitpid(char *proc, pid_t p, int *status, int options) { 394 | pid_t wpid; 395 | if ((wpid = waitpid(p, status, options)) < 0) 396 | ic_plog(SINF, "(%s) waitpid failure (%s)", proc, strerror(errno)); 397 | 398 | return (wpid); 399 | } 400 | 401 | 402 | /*------------------------------------------------------------------------- 403 | * read with error check 404 | * 405 | *------------------------------------------------------------------------- 406 | */ 407 | ssize_t 408 | xread(int fd, void *buff, size_t size) 409 | { 410 | size_t left; 411 | ssize_t nread; 412 | 413 | void *p; 414 | 415 | p = buff; 416 | left = size; 417 | 418 | while (left > 0) { 419 | if ((nread = read(fd, p, left)) < 0) { 420 | if (errno == EINTR) 421 | nread = 0; 422 | else 423 | return (-1); 424 | } 425 | else if (nread == 0) { 426 | break; 427 | } 428 | left -= nread; 429 | p = (char *)p + nread; 430 | } 431 | 432 | return (size - left); 433 | } 434 | 435 | 436 | /*------------------------------------------------------------------------- 437 | * write with error check 438 | * 439 | *------------------------------------------------------------------------- 440 | */ 441 | ssize_t 442 | xwrite(int fd, void *buff, size_t size) 443 | { 444 | size_t left; 445 | ssize_t nwrite; 446 | 447 | void *p; 448 | 449 | p = buff; 450 | left = size; 451 | 452 | while (left > 0) { 453 | if ((nwrite = write(fd, p, left)) < 0) { 454 | if (errno == EINTR) 455 | nwrite = 0; 456 | else 457 | return (-1); 458 | } 459 | left -= nwrite; 460 | p = (char *)p + nwrite; 461 | } 462 | 463 | return size; 464 | } 465 | 466 | 467 | /*------------------------------------------------------------------------- 468 | * syslog interface 469 | * 470 | *------------------------------------------------------------------------- 471 | */ 472 | void 473 | vsys_err(int priority, const char *format, ...) 474 | { 475 | va_list ap; 476 | 477 | va_start(ap, format); 478 | vsyslog(priority, format, ap); 479 | 480 | va_end(ap); 481 | 482 | exit(1); 483 | } 484 | 485 | void 486 | vsys(int priority, const char *format, ...) 487 | { 488 | va_list ap; 489 | 490 | va_start(ap, format); 491 | vsyslog(priority, format, ap); 492 | 493 | va_end(ap); 494 | 495 | return; 496 | } 497 | 498 | 499 | /*------------------------------------------------------------------------- 500 | * internet checksum 501 | * 502 | *------------------------------------------------------------------------- 503 | */ 504 | u_short 505 | xchecksum(u_short *addr, int len) { 506 | u_short answer; 507 | u_short *w; 508 | int nleft, sum; 509 | 510 | nleft = len; 511 | sum = 0; 512 | w = addr; 513 | while (nleft > 1) { 514 | sum += *(w++); 515 | nleft -= 2; 516 | } 517 | if (nleft == 1) 518 | sum += *(u_char *) w; 519 | 520 | sum = (sum & 0xffff) + (sum >> 16); 521 | sum += (sum >> 16); 522 | answer = ~sum; 523 | 524 | return (answer); 525 | } 526 | 527 | 528 | /*------------------------------------------------------------------------- 529 | * fork with error check 530 | * 531 | *------------------------------------------------------------------------- 532 | */ 533 | pid_t 534 | xfork(void) 535 | { 536 | pid_t pid; 537 | 538 | if ((pid = fork()) < 0) { 539 | ic_plog(SERR, "xfork failure due to fork error"); 540 | exit(1); 541 | } 542 | 543 | return (pid); 544 | } 545 | 546 | 547 | /*------------------------------------------------------------------------- 548 | * malloc family with error check 549 | * 550 | *------------------------------------------------------------------------- 551 | */ 552 | void * 553 | xmalloc(size_t size) 554 | { 555 | void *tmp; 556 | 557 | if (!size) { 558 | ic_plog(SERR, "xmalloc failure due to invalid size"); 559 | exit (1); 560 | } 561 | 562 | if ((tmp = malloc(size)) == NULL) { 563 | ic_plog(SERR, "xmalloc failure due to malloc error"); 564 | exit (1); 565 | } 566 | else { 567 | memset(tmp, 0, size); 568 | } 569 | 570 | return (tmp); 571 | } 572 | 573 | void * 574 | xrealloc(void *src, size_t size) 575 | { 576 | void *dst; 577 | 578 | if (!size) { 579 | ic_plog(SERR, "xrealloc failure due to invalid size"); 580 | exit (1); 581 | } 582 | 583 | if ((dst = realloc(src, size)) == NULL) { 584 | ic_plog(SERR, "xrealloc failure due to realloc error"); 585 | exit (1); 586 | } 587 | 588 | return (dst); 589 | } 590 | 591 | 592 | /*------------------------------------------------------------------------- 593 | * strdup with error check 594 | * 595 | *------------------------------------------------------------------------- 596 | */ 597 | char * 598 | xstrdup(char *ptr) 599 | { 600 | char *tmp; 601 | 602 | if (!ptr) { 603 | ic_plog(SERR, "xstrdup failure due to invalid pointer"); 604 | exit (1); 605 | } 606 | 607 | if ((tmp = strdup(ptr)) == NULL) { 608 | ic_plog(SERR, "xstrdup failure due to strdup error"); 609 | exit (1); 610 | } 611 | 612 | return (tmp); 613 | } 614 | 615 | 616 | /* end of source */ 617 | --------------------------------------------------------------------------------