/src/dropbear/src/tcp-accept.c
Line | Count | Source |
1 | | /* |
2 | | * Dropbear SSH |
3 | | * |
4 | | * Copyright (c) 2002,2003 Matt Johnston |
5 | | * All rights reserved. |
6 | | * |
7 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
8 | | * of this software and associated documentation files (the "Software"), to deal |
9 | | * in the Software without restriction, including without limitation the rights |
10 | | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
11 | | * copies of the Software, and to permit persons to whom the Software is |
12 | | * furnished to do so, subject to the following conditions: |
13 | | * |
14 | | * The above copyright notice and this permission notice shall be included in |
15 | | * all copies or substantial portions of the Software. |
16 | | * |
17 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
18 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
19 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
20 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
21 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
22 | | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
23 | | * SOFTWARE. */ |
24 | | |
25 | | #include "includes.h" |
26 | | #include "ssh.h" |
27 | | #include "tcpfwd.h" |
28 | | #include "dbutil.h" |
29 | | #include "session.h" |
30 | | #include "buffer.h" |
31 | | #include "packet.h" |
32 | | #include "listener.h" |
33 | | #include "listener.h" |
34 | | #include "runopts.h" |
35 | | |
36 | | #if DROPBEAR_TCP_ACCEPT |
37 | | |
38 | 0 | static void cleanup_tcp(const struct Listener *listener) { |
39 | |
|
40 | 0 | struct TCPListener *tcpinfo = (struct TCPListener*)(listener->typedata); |
41 | |
|
42 | 0 | m_free(tcpinfo->sendaddr); |
43 | 0 | m_free(tcpinfo->listenaddr); |
44 | 0 | m_free(tcpinfo->request_listenaddr); |
45 | 0 | m_free(tcpinfo); |
46 | 0 | } |
47 | | |
48 | 0 | static void tcp_acceptor(const struct Listener *listener, int sock) { |
49 | |
|
50 | 0 | int fd; |
51 | 0 | struct sockaddr_storage sa; |
52 | 0 | socklen_t len; |
53 | 0 | char ipstring[NI_MAXHOST], portstring[NI_MAXSERV]; |
54 | 0 | struct TCPListener *tcpinfo = (struct TCPListener*)(listener->typedata); |
55 | |
|
56 | 0 | len = sizeof(sa); |
57 | |
|
58 | 0 | fd = accept(sock, (struct sockaddr*)&sa, &len); |
59 | 0 | if (fd < 0) { |
60 | 0 | return; |
61 | 0 | } |
62 | | |
63 | 0 | if (getnameinfo((struct sockaddr*)&sa, len, ipstring, sizeof(ipstring), |
64 | 0 | portstring, sizeof(portstring), |
65 | 0 | NI_NUMERICHOST | NI_NUMERICSERV) != 0) { |
66 | 0 | m_close(fd); |
67 | 0 | return; |
68 | 0 | } |
69 | | |
70 | 0 | if (send_msg_channel_open_init(fd, tcpinfo->chantype) == DROPBEAR_SUCCESS) { |
71 | 0 | char* addr = NULL; |
72 | 0 | unsigned int port = 0; |
73 | |
|
74 | 0 | if (tcpinfo->tcp_type == direct) { |
75 | | /* "direct-tcpip" */ |
76 | | /* host to connect, port to connect */ |
77 | 0 | addr = tcpinfo->sendaddr; |
78 | 0 | port = tcpinfo->sendport; |
79 | 0 | } else { |
80 | 0 | dropbear_assert(tcpinfo->tcp_type == forwarded); |
81 | | /* "forwarded-tcpip" */ |
82 | | /* address that was connected, port that was connected */ |
83 | 0 | addr = tcpinfo->request_listenaddr; |
84 | 0 | port = tcpinfo->listenport; |
85 | 0 | } |
86 | | |
87 | 0 | if (addr == NULL) { |
88 | 0 | addr = "localhost"; |
89 | 0 | } |
90 | 0 | buf_putstring(ses.writepayload, addr, strlen(addr)); |
91 | 0 | buf_putint(ses.writepayload, port); |
92 | | |
93 | | /* originator ip */ |
94 | 0 | buf_putstring(ses.writepayload, ipstring, strlen(ipstring)); |
95 | | /* originator port */ |
96 | 0 | buf_putint(ses.writepayload, atol(portstring)); |
97 | |
|
98 | 0 | encrypt_packet(); |
99 | |
|
100 | 0 | } else { |
101 | | /* XXX debug? */ |
102 | 0 | close(fd); |
103 | 0 | } |
104 | 0 | } |
105 | | |
106 | 0 | int listen_tcpfwd(struct TCPListener* tcpinfo, struct Listener **ret_listener) { |
107 | |
|
108 | 0 | char portstring[NI_MAXSERV]; |
109 | 0 | int socks[DROPBEAR_MAX_SOCKS]; |
110 | 0 | int nsocks; |
111 | 0 | struct Listener *listener; |
112 | 0 | char* errstring = NULL; |
113 | |
|
114 | 0 | TRACE(("enter listen_tcpfwd")) |
115 | | |
116 | | /* first we try to bind, so don't need to do so much cleanup on failure */ |
117 | 0 | snprintf(portstring, sizeof(portstring), "%u", tcpinfo->listenport); |
118 | |
|
119 | 0 | nsocks = dropbear_listen(tcpinfo->listenaddr, portstring, socks, |
120 | 0 | DROPBEAR_MAX_SOCKS, &errstring, &ses.maxfd, tcpinfo->interface); |
121 | 0 | if (nsocks < 0) { |
122 | 0 | dropbear_log(LOG_INFO, "TCP forward failed: %s", errstring); |
123 | 0 | m_free(errstring); |
124 | 0 | TRACE(("leave listen_tcpfwd: dropbear_listen failed")) |
125 | 0 | return DROPBEAR_FAILURE; |
126 | 0 | } |
127 | 0 | m_free(errstring); |
128 | | |
129 | | /* new_listener will close the socks if it fails */ |
130 | 0 | listener = new_listener(socks, nsocks, CHANNEL_ID_TCPFORWARDED, tcpinfo, |
131 | 0 | tcp_acceptor, cleanup_tcp); |
132 | |
|
133 | 0 | if (listener == NULL) { |
134 | 0 | TRACE(("leave listen_tcpfwd: listener failed")) |
135 | 0 | return DROPBEAR_FAILURE; |
136 | 0 | } |
137 | | |
138 | 0 | if (ret_listener) { |
139 | 0 | *ret_listener = listener; |
140 | 0 | } |
141 | |
|
142 | 0 | TRACE(("leave listen_tcpfwd: success")) |
143 | 0 | return DROPBEAR_SUCCESS; |
144 | 0 | } |
145 | | |
146 | | #endif /* DROPBEAR_TCP_ACCEPT */ |