diff options
author | Ben Lindstrom <mouring@eviladmin.org> | 2001-04-11 15:57:50 +0000 |
---|---|---|
committer | Ben Lindstrom <mouring@eviladmin.org> | 2001-04-11 15:57:50 +0000 |
commit | b39215168584a1601a47356697963d808614990a (patch) | |
tree | 1b237dea2f9c89b6c40c40ab26c94ad31d40668f | |
parent | 1a598a459770245946505c17e89c1200bc9be949 (diff) |
- markus@cvs.openbsd.org 2001/04/10 07:46:58
[channels.c]
cleanup socks4 handling
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | channels.c | 186 |
2 files changed, 124 insertions, 70 deletions
@@ -1,3 +1,9 @@ | |||
1 | 20010412 | ||
2 | - OpenBSD CVS Sync | ||
3 | - markus@cvs.openbsd.org 2001/04/10 07:46:58 | ||
4 | [channels.c] | ||
5 | cleanup socks4 handling | ||
6 | |||
1 | 20010410 | 7 | 20010410 |
2 | - OpenBSD CVS Sync | 8 | - OpenBSD CVS Sync |
3 | - deraadt@cvs.openbsd.org 2001/04/08 20:52:55 | 9 | - deraadt@cvs.openbsd.org 2001/04/08 20:52:55 |
@@ -4990,4 +4996,4 @@ | |||
4990 | - Wrote replacements for strlcpy and mkdtemp | 4996 | - Wrote replacements for strlcpy and mkdtemp |
4991 | - Released 1.0pre1 | 4997 | - Released 1.0pre1 |
4992 | 4998 | ||
4993 | $Id: ChangeLog,v 1.1093 2001/04/10 02:48:50 mouring Exp $ | 4999 | $Id: ChangeLog,v 1.1094 2001/04/11 15:57:50 mouring Exp $ |
diff --git a/channels.c b/channels.c index 0e334db88..008ff64b9 100644 --- a/channels.c +++ b/channels.c | |||
@@ -40,7 +40,7 @@ | |||
40 | */ | 40 | */ |
41 | 41 | ||
42 | #include "includes.h" | 42 | #include "includes.h" |
43 | RCSID("$OpenBSD: channels.c,v 1.103 2001/04/07 08:55:17 markus Exp $"); | 43 | RCSID("$OpenBSD: channels.c,v 1.104 2001/04/10 07:46:58 markus Exp $"); |
44 | 44 | ||
45 | #include <openssl/rsa.h> | 45 | #include <openssl/rsa.h> |
46 | #include <openssl/dsa.h> | 46 | #include <openssl/dsa.h> |
@@ -542,88 +542,142 @@ channel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset) | |||
542 | } | 542 | } |
543 | } | 543 | } |
544 | 544 | ||
545 | #define SSH_SOCKS_HEAD 1+1+2+4 | ||
546 | 545 | ||
547 | void | 546 | int |
548 | channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) | 547 | channel_decode_helper(Channel *c, int start, int lookfor) |
548 | { | ||
549 | u_char *p; | ||
550 | int i, have; | ||
551 | |||
552 | p = buffer_ptr(&c->input); | ||
553 | have = buffer_len(&c->input); | ||
554 | debug2("channel %d: decode_helper: start %d have %d lookfor %d", | ||
555 | c->self, start, have, lookfor); | ||
556 | if (have < start) | ||
557 | return 0; | ||
558 | for (i = start; i < have; i++) { | ||
559 | if (p[i] == lookfor) { | ||
560 | debug2("channel %d: decode_helper: matched at %d", | ||
561 | c->self, i); | ||
562 | if (lookfor == '\0' || | ||
563 | (i+3 < have && | ||
564 | p[i+1] == '\n' && | ||
565 | p[i+2] == '\r' && | ||
566 | p[i+3] == '\n')) | ||
567 | return i; | ||
568 | } | ||
569 | if (i > 4096) { | ||
570 | /* the peer is probably sending garbage */ | ||
571 | debug("channel %d: decode_helper: too long", | ||
572 | c->self); | ||
573 | return -1; | ||
574 | } | ||
575 | } | ||
576 | return 0; /* need more */ | ||
577 | } | ||
578 | |||
579 | /* try to decode a socks4 header */ | ||
580 | int | ||
581 | channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset) | ||
549 | { | 582 | { |
550 | u_char *p, *host; | 583 | u_char *p, *host; |
551 | int len, i, done, have; | 584 | int len, have, ret; |
552 | char username[256]; | 585 | char username[256]; |
553 | struct { | 586 | struct { |
554 | u_int8_t version; | 587 | u_int8_t version; |
555 | u_int8_t command; | 588 | u_int8_t command; |
556 | u_int16_t dest_port; | 589 | u_int16_t dest_port; |
557 | struct in_addr dest_ip; | 590 | struct in_addr dest_addr; |
558 | } s4_req, s4_rsp; | 591 | } s4_req, s4_rsp; |
559 | 592 | ||
560 | have = buffer_len(&c->input); | 593 | debug2("channel %d: decode socks4", c->self); |
561 | 594 | ret = channel_decode_helper(c, sizeof(s4_req), '\0'); | |
562 | debug("channel %d: pre_dynamic have: %d", c->self, have); | 595 | if (ret <= 0) |
563 | /*buffer_dump(&c->input);*/ | 596 | return ret; |
564 | |||
565 | /* Check if the fixed size part of the packet is in buffer. */ | ||
566 | if (have < SSH_SOCKS_HEAD + 1) { | ||
567 | /* need more */ | ||
568 | FD_SET(c->sock, readset); | ||
569 | return; | ||
570 | } | ||
571 | /* Check for end of username */ | ||
572 | p = buffer_ptr(&c->input); | ||
573 | done = 0; | ||
574 | for (i = SSH_SOCKS_HEAD; i < have; i++) { | ||
575 | if (p[i] == '\0') { | ||
576 | done = 1; | ||
577 | break; | ||
578 | } | ||
579 | } | ||
580 | if (!done) { | ||
581 | /* need more */ | ||
582 | FD_SET(c->sock, readset); | ||
583 | return; | ||
584 | } | ||
585 | buffer_get(&c->input, (char *)&s4_req.version, 1); | 597 | buffer_get(&c->input, (char *)&s4_req.version, 1); |
586 | buffer_get(&c->input, (char *)&s4_req.command, 1); | 598 | buffer_get(&c->input, (char *)&s4_req.command, 1); |
587 | buffer_get(&c->input, (char *)&s4_req.dest_port, 2); | 599 | buffer_get(&c->input, (char *)&s4_req.dest_port, 2); |
588 | buffer_get(&c->input, (char *)&s4_req.dest_ip, 4); | 600 | buffer_get(&c->input, (char *)&s4_req.dest_addr, 4); |
589 | p = buffer_ptr(&c->input); | 601 | p = buffer_ptr(&c->input); |
590 | len = strlen(p); | 602 | len = strlen(p); |
591 | have = buffer_len(&c->input); | 603 | have = buffer_len(&c->input); |
592 | debug2("channel %d: pre_dynamic user: %s/%d", c->self, p, len); | 604 | debug2("channel %d: pre_dynamic: user %s/%d", c->self, p, len); |
593 | if (len > have) | 605 | if (len > have) |
594 | fatal("channel %d: pre_dynamic: len %d > have %d", | 606 | fatal("channel %d: decode socks4: len %d > have %d", |
595 | c->self, len, have); | 607 | c->self, len, have); |
596 | strlcpy(username, p, sizeof(username)); | 608 | strlcpy(username, p, sizeof(username)); |
597 | buffer_consume(&c->input, len); | 609 | buffer_consume(&c->input, len); |
598 | buffer_consume(&c->input, 1); /* trailing '\0' */ | 610 | buffer_consume(&c->input, 1); /* trailing '\0' */ |
599 | 611 | ||
600 | host = inet_ntoa(s4_req.dest_ip); | 612 | host = inet_ntoa(s4_req.dest_addr); |
601 | strlcpy(c->path, host, sizeof(c->path)); | 613 | strlcpy(c->path, host, sizeof(c->path)); |
602 | c->host_port = ntohs(s4_req.dest_port); | 614 | c->host_port = ntohs(s4_req.dest_port); |
603 | 615 | ||
604 | debug("channel %d: dynamic request received: " | 616 | debug("channel %d: dynamic request: " |
605 | "socks%x://%s@%s:%u/command?%u", | 617 | "socks%x://%s@%s:%u/command?%u", |
606 | c->self, s4_req.version, username, host, c->host_port, | 618 | c->self, s4_req.version, username, host, c->host_port, |
607 | s4_req.command); | 619 | s4_req.command); |
608 | 620 | ||
609 | if ((s4_req.version != 4) || (s4_req.command != 1)) { | 621 | if (s4_req.command != 1) { |
610 | debug("channel %d: cannot handle: socks VN %d CN %d", | 622 | debug("channel %d: cannot handle: socks4 cn %d", |
611 | c->self, s4_req.version, s4_req.command); | 623 | c->self, s4_req.command); |
612 | channel_free(c->self); | 624 | return -1; |
613 | return; | ||
614 | } | 625 | } |
615 | 626 | s4_rsp.version = 0; /* vn: 0 for reply */ | |
616 | s4_rsp.version = 0; /* VN: version of reply code */ | 627 | s4_rsp.command = 90; /* cd: req granted */ |
617 | s4_rsp.command = 90; /* CD: request granted */ | ||
618 | s4_rsp.dest_port = 0; /* ignored */ | 628 | s4_rsp.dest_port = 0; /* ignored */ |
619 | s4_rsp.dest_ip.s_addr = INADDR_ANY; /* ignored */ | 629 | s4_rsp.dest_addr.s_addr = INADDR_ANY; /* ignored */ |
620 | buffer_append(&c->output, (char *)&s4_rsp, sizeof(s4_rsp)); | 630 | buffer_append(&c->output, (char *)&s4_rsp, sizeof(s4_rsp)); |
621 | 631 | return 1; | |
622 | /* switch to next state */ | ||
623 | c->type = SSH_CHANNEL_OPENING; | ||
624 | port_open_helper(c, "direct-tcpip"); | ||
625 | } | 632 | } |
626 | 633 | ||
634 | /* dynamic port forwarding */ | ||
635 | void | ||
636 | channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) | ||
637 | { | ||
638 | u_char *p; | ||
639 | int have, ret; | ||
640 | |||
641 | have = buffer_len(&c->input); | ||
642 | |||
643 | debug2("channel %d: pre_dynamic: have %d", c->self, have); | ||
644 | buffer_dump(&c->input); | ||
645 | /* check if the fixed size part of the packet is in buffer. */ | ||
646 | if (have < 4) { | ||
647 | /* need more */ | ||
648 | FD_SET(c->sock, readset); | ||
649 | return; | ||
650 | } | ||
651 | /* try to guess the protocol */ | ||
652 | p = buffer_ptr(&c->input); | ||
653 | switch (p[0]) { | ||
654 | case 0x04: | ||
655 | ret = channel_decode_socks4(c, readset, writeset); | ||
656 | break; | ||
657 | #if 0 | ||
658 | case 'C': | ||
659 | ret = channel_decode_https(c, readset, writeset); | ||
660 | break; | ||
661 | case 0x05: | ||
662 | ret = channel_decode_socks5(c, readset, writeset); | ||
663 | break; | ||
664 | #endif | ||
665 | default: | ||
666 | ret = -1; | ||
667 | break; | ||
668 | } | ||
669 | if (ret < 0) { | ||
670 | channel_free(c->self); | ||
671 | } else if (ret == 0) { | ||
672 | debug2("channel %d: pre_dynamic: need more", c->self); | ||
673 | /* need more */ | ||
674 | FD_SET(c->sock, readset); | ||
675 | } else { | ||
676 | /* switch to the next state */ | ||
677 | c->type = SSH_CHANNEL_OPENING; | ||
678 | port_open_helper(c, "direct-tcpip"); | ||
679 | } | ||
680 | } | ||
627 | 681 | ||
628 | /* This is our fake X11 server socket. */ | 682 | /* This is our fake X11 server socket. */ |
629 | void | 683 | void |
@@ -846,16 +900,11 @@ channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset) | |||
846 | if (len <= 0) { | 900 | if (len <= 0) { |
847 | debug("channel %d: read<=0 rfd %d len %d", | 901 | debug("channel %d: read<=0 rfd %d len %d", |
848 | c->self, c->rfd, len); | 902 | c->self, c->rfd, len); |
849 | if (c->type == SSH_CHANNEL_DYNAMIC) { | 903 | if (c->type != SSH_CHANNEL_OPEN) { |
850 | /* | 904 | debug("channel %d: not open", c->self); |
851 | * we are not yet connected to a remote peer, | ||
852 | * so the connection-close protocol won't work | ||
853 | */ | ||
854 | debug("channel %d: dynamic: closed", c->self); | ||
855 | channel_free(c->self); | 905 | channel_free(c->self); |
856 | return -1; | 906 | return -1; |
857 | } | 907 | } else if (compat13) { |
858 | if (compat13) { | ||
859 | buffer_consume(&c->output, buffer_len(&c->output)); | 908 | buffer_consume(&c->output, buffer_len(&c->output)); |
860 | c->type = SSH_CHANNEL_INPUT_DRAINING; | 909 | c->type = SSH_CHANNEL_INPUT_DRAINING; |
861 | debug("Channel %d status set to input draining.", c->self); | 910 | debug("Channel %d status set to input draining.", c->self); |
@@ -890,7 +939,11 @@ channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset) | |||
890 | if (len < 0 && (errno == EINTR || errno == EAGAIN)) | 939 | if (len < 0 && (errno == EINTR || errno == EAGAIN)) |
891 | return 1; | 940 | return 1; |
892 | if (len <= 0) { | 941 | if (len <= 0) { |
893 | if (compat13) { | 942 | if (c->type != SSH_CHANNEL_OPEN) { |
943 | debug("channel %d: not open", c->self); | ||
944 | channel_free(c->self); | ||
945 | return -1; | ||
946 | } else if (compat13) { | ||
894 | buffer_consume(&c->output, buffer_len(&c->output)); | 947 | buffer_consume(&c->output, buffer_len(&c->output)); |
895 | debug("Channel %d status set to input draining.", c->self); | 948 | debug("Channel %d status set to input draining.", c->self); |
896 | c->type = SSH_CHANNEL_INPUT_DRAINING; | 949 | c->type = SSH_CHANNEL_INPUT_DRAINING; |
@@ -967,7 +1020,8 @@ channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset) | |||
967 | int | 1020 | int |
968 | channel_check_window(Channel *c) | 1021 | channel_check_window(Channel *c) |
969 | { | 1022 | { |
970 | if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) && | 1023 | if (c->type == SSH_CHANNEL_OPEN && |
1024 | !(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) && | ||
971 | c->local_window < c->local_window_max/2 && | 1025 | c->local_window < c->local_window_max/2 && |
972 | c->local_consumed > 0) { | 1026 | c->local_consumed > 0) { |
973 | packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); | 1027 | packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); |
@@ -1016,12 +1070,6 @@ channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset) | |||
1016 | } | 1070 | } |
1017 | 1071 | ||
1018 | void | 1072 | void |
1019 | channel_post_dynamic(Channel *c, fd_set * readset, fd_set * writeset) | ||
1020 | { | ||
1021 | channel_handle_rfd(c, readset, writeset); | ||
1022 | } | ||
1023 | |||
1024 | void | ||
1025 | channel_handler_init_20(void) | 1073 | channel_handler_init_20(void) |
1026 | { | 1074 | { |
1027 | channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_20; | 1075 | channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_20; |
@@ -1039,7 +1087,7 @@ channel_handler_init_20(void) | |||
1039 | channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; | 1087 | channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; |
1040 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; | 1088 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; |
1041 | channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; | 1089 | channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; |
1042 | channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_dynamic; | 1090 | channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open_2; |
1043 | } | 1091 | } |
1044 | 1092 | ||
1045 | void | 1093 | void |
@@ -1061,7 +1109,7 @@ channel_handler_init_13(void) | |||
1061 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; | 1109 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; |
1062 | channel_post[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_post_output_drain_13; | 1110 | channel_post[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_post_output_drain_13; |
1063 | channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; | 1111 | channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; |
1064 | channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_dynamic; | 1112 | channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open_1; |
1065 | } | 1113 | } |
1066 | 1114 | ||
1067 | void | 1115 | void |
@@ -1080,7 +1128,7 @@ channel_handler_init_15(void) | |||
1080 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; | 1128 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; |
1081 | channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_1; | 1129 | channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_1; |
1082 | channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; | 1130 | channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; |
1083 | channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_dynamic; | 1131 | channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open_1; |
1084 | } | 1132 | } |
1085 | 1133 | ||
1086 | void | 1134 | void |