summaryrefslogtreecommitdiff
path: root/channels.c
diff options
context:
space:
mode:
Diffstat (limited to 'channels.c')
-rw-r--r--channels.c160
1 files changed, 149 insertions, 11 deletions
diff --git a/channels.c b/channels.c
index 4283abc3a..a1aa937ae 100644
--- a/channels.c
+++ b/channels.c
@@ -40,7 +40,7 @@
40 */ 40 */
41 41
42#include "includes.h" 42#include "includes.h"
43RCSID("$OpenBSD: channels.c,v 1.105 2001/04/10 12:15:23 markus Exp $"); 43RCSID("$OpenBSD: channels.c,v 1.106 2001/04/11 13:56:13 markus Exp $");
44 44
45#include <openssl/rsa.h> 45#include <openssl/rsa.h>
46#include <openssl/dsa.h> 46#include <openssl/dsa.h>
@@ -576,6 +576,39 @@ channel_decode_helper(Channel *c, int start, int lookfor)
576 return 0; /* need more */ 576 return 0; /* need more */
577} 577}
578 578
579/* try to decode a http connect header */
580int
581channel_decode_https(Channel *c, fd_set * readset, fd_set * writeset)
582{
583 u_char *p, *host, *buf;
584 int port, ret;
585 char httpok[] = "HTTP/1.0 200\r\n\r\n";
586
587 debug2("channel %d: decode https connect", c->self);
588 ret = channel_decode_helper(c, strlen("connect "), '\r');
589 if (ret <= 0)
590 return ret;
591 p = buffer_ptr(&c->input);
592 buf = xmalloc(ret+1);
593 host = xmalloc(ret);
594 memcpy(buf, p, ret);
595 buf[ret] = '\0';
596 if (sscanf(buf, "CONNECT %[^:]:%u HTTP/", host, &port) != 2) {
597 debug("channel %d: cannot parse http header", c->self);
598 return -1;
599 }
600 debug("channel %d: dynamic request: https host %s port %u",
601 c->self, host, port);
602 strlcpy(c->path, host, sizeof(c->path));
603 c->host_port = port;
604 xfree(host);
605 xfree(buf);
606 buffer_consume(&c->input, ret+4);
607 buffer_append(&c->output, httpok, strlen(httpok));
608
609 return 1;
610}
611
579/* try to decode a socks4 header */ 612/* try to decode a socks4 header */
580int 613int
581channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset) 614channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset)
@@ -601,7 +634,7 @@ channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset)
601 p = buffer_ptr(&c->input); 634 p = buffer_ptr(&c->input);
602 len = strlen(p); 635 len = strlen(p);
603 have = buffer_len(&c->input); 636 have = buffer_len(&c->input);
604 debug2("channel %d: pre_dynamic: user %s/%d", c->self, p, len); 637 debug2("channel %d: decode socks4: user %s/%d", c->self, p, len);
605 if (len > have) 638 if (len > have)
606 fatal("channel %d: decode socks4: len %d > have %d", 639 fatal("channel %d: decode socks4: len %d > have %d",
607 c->self, len, have); 640 c->self, len, have);
@@ -613,10 +646,8 @@ channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset)
613 strlcpy(c->path, host, sizeof(c->path)); 646 strlcpy(c->path, host, sizeof(c->path));
614 c->host_port = ntohs(s4_req.dest_port); 647 c->host_port = ntohs(s4_req.dest_port);
615 648
616 debug("channel %d: dynamic request: " 649 debug("channel %d: dynamic request: socks4 host %s port %u command %u",
617 "socks%x://%s@%s:%u/command?%u", 650 c->self, host, c->host_port, s4_req.command);
618 c->self, s4_req.version, username, host, c->host_port,
619 s4_req.command);
620 651
621 if (s4_req.command != 1) { 652 if (s4_req.command != 1) {
622 debug("channel %d: cannot handle: socks4 cn %d", 653 debug("channel %d: cannot handle: socks4 cn %d",
@@ -631,6 +662,115 @@ channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset)
631 return 1; 662 return 1;
632} 663}
633 664
665/* try to decode a socks5 header */
666#define SSH_SOCKS5_AUTHDONE 0x1000
667#define SSH_SOCKS5_NOAUTH 0x00
668#define SSH_SOCKS5_IPV4 0x01
669#define SSH_SOCKS5_DOMAIN 0x03
670#define SSH_SOCKS5_IPV6 0x04
671#define SSH_SOCKS5_CONNECT 0x01
672#define SSH_SOCKS5_SUCCESS 0x00
673
674int
675channel_decode_socks5(Channel *c, fd_set * readset, fd_set * writeset)
676{
677 struct {
678 u_int8_t version;
679 u_int8_t command;
680 u_int8_t reserved;
681 u_int8_t atyp;
682 } s5_req, s5_rsp;
683 u_int16_t dest_port;
684 u_char *p, dest_addr[255+1];
685 int i, have, found, nmethods, addrlen, af;
686
687 debug2("channel %d: decode socks5", c->self);
688 p = buffer_ptr(&c->input);
689 if (p[0] != 0x05)
690 return -1;
691 have = buffer_len(&c->input);
692 if (!(c->flags & SSH_SOCKS5_AUTHDONE)) {
693 /* format: ver | nmethods | methods */
694 if (have < 2)
695 return 0;
696 nmethods = p[1];
697 if (have < nmethods + 2)
698 return 0;
699 /* look for method: "NO AUTHENTICATION REQUIRED" */
700 for (found = 0, i = 2 ; i < nmethods + 2; i++) {
701 if (p[i] == SSH_SOCKS5_NOAUTH ) {
702 found = 1;
703 break;
704 }
705 }
706 if (!found) {
707 debug("channel %d: method SSH_SOCKS5_NOAUTH not found",
708 c->self);
709 return -1;
710 }
711 buffer_consume(&c->input, nmethods + 2);
712 buffer_put_char(&c->output, 0x05); /* version */
713 buffer_put_char(&c->output, SSH_SOCKS5_NOAUTH); /* method */
714 FD_SET(c->sock, writeset);
715 c->flags |= SSH_SOCKS5_AUTHDONE;
716 debug2("channel %d: socks5 auth done", c->self);
717 return 0; /* need more */
718 }
719 debug2("channel %d: socks5 post auth", c->self);
720 if (have < sizeof(s5_req)+1)
721 return 0; /* need more */
722 memcpy((char *)&s5_req, p, sizeof(s5_req));
723 if (s5_req.version != 0x05 ||
724 s5_req.command != SSH_SOCKS5_CONNECT ||
725 s5_req.reserved != 0x00) {
726 debug("channel %d: only socks5 connect supported", c->self);
727 return -1;
728 }
729 switch(s5_req.atyp){
730 case SSH_SOCKS5_IPV4:
731 addrlen = 4;
732 af = AF_INET;
733 break;
734 case SSH_SOCKS5_DOMAIN:
735 addrlen = p[sizeof(s5_req)];
736 af = -1;
737 break;
738 case SSH_SOCKS5_IPV6:
739 addrlen = 16;
740 af = AF_INET6;
741 break;
742 default:
743 debug("channel %d: bad socks5 atyp %d", c->self, s5_req.atyp);
744 return -1;
745 }
746 if (have < 4 + addrlen + 2)
747 return 0;
748 buffer_consume(&c->input, sizeof(s5_req));
749 buffer_get(&c->input, (char *)&dest_addr, addrlen);
750 buffer_get(&c->input, (char *)&dest_port, 2);
751 dest_addr[addrlen] = '\0';
752 if (s5_req.atyp == SSH_SOCKS5_DOMAIN)
753 strlcpy(c->path, dest_addr, sizeof(c->path));
754 else if (inet_ntop(af, dest_addr, c->path, sizeof(c->path)) == NULL)
755 return -1;
756 c->host_port = ntohs(dest_port);
757
758 debug("channel %d: dynamic request: socks5 host %s port %u command %u",
759 c->self, c->path, c->host_port, s5_req.command);
760
761 s5_rsp.version = 0x05;
762 s5_rsp.command = SSH_SOCKS5_SUCCESS;
763 s5_rsp.reserved = 0; /* ignored */
764 s5_rsp.atyp = SSH_SOCKS5_IPV4;
765 ((struct in_addr *)&dest_addr)->s_addr = INADDR_ANY;
766 dest_port = 0; /* ignored */
767
768 buffer_append(&c->output, (char *)&s5_rsp, sizeof(s5_rsp));
769 buffer_append(&c->output, (char *)&dest_addr, sizeof(struct in_addr));
770 buffer_append(&c->output, (char *)&dest_port, sizeof(dest_port));
771 return 1;
772}
773
634/* dynamic port forwarding */ 774/* dynamic port forwarding */
635void 775void
636channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) 776channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset)
@@ -651,17 +791,15 @@ channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset)
651 /* try to guess the protocol */ 791 /* try to guess the protocol */
652 p = buffer_ptr(&c->input); 792 p = buffer_ptr(&c->input);
653 switch (p[0]) { 793 switch (p[0]) {
654 case 0x04:
655 ret = channel_decode_socks4(c, readset, writeset);
656 break;
657#if 0
658 case 'C': 794 case 'C':
659 ret = channel_decode_https(c, readset, writeset); 795 ret = channel_decode_https(c, readset, writeset);
660 break; 796 break;
797 case 0x04:
798 ret = channel_decode_socks4(c, readset, writeset);
799 break;
661 case 0x05: 800 case 0x05:
662 ret = channel_decode_socks5(c, readset, writeset); 801 ret = channel_decode_socks5(c, readset, writeset);
663 break; 802 break;
664#endif
665 default: 803 default:
666 ret = -1; 804 ret = -1;
667 break; 805 break;