Mercurial > dropbear
comparison svr-tcpfwd.c @ 673:c519b78b6d1a
- Don't sent SSH_MSG_UNIMPLEMENTED if we don't have ENABLE_SVR_REMOTETCPFWD
- Fix build if ENABLE_SVR_REMOTETCPFWD is disabled but ENABLE_SVR_LOCALTCPFWD
is enabled
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Wed, 09 May 2012 20:33:16 +0800 |
parents | 79d48028457c |
children | dfdb9d9189ff |
comparison
equal
deleted
inserted
replaced
672:6c35ff40e496 | 673:c519b78b6d1a |
---|---|
32 #include "packet.h" | 32 #include "packet.h" |
33 #include "listener.h" | 33 #include "listener.h" |
34 #include "runopts.h" | 34 #include "runopts.h" |
35 #include "auth.h" | 35 #include "auth.h" |
36 | 36 |
37 #ifdef ENABLE_SVR_REMOTETCPFWD | 37 static void send_msg_request_failure(); |
38 | |
39 static void send_msg_request_failure() { | |
40 CHECKCLEARTOWRITE(); | |
41 buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE); | |
42 encrypt_packet(); | |
43 } | |
44 | |
45 #ifndef ENABLE_SVR_REMOTETCPFWD | |
46 | |
47 /* This is better than SSH_MSG_UNIMPLEMENTED */ | |
48 void recv_msg_global_request_remotetcp() { | |
49 TRACE(("recv_msg_global_request_remotetcp: remote tcp forwarding not compiled in")) | |
50 send_msg_request_failure(); | |
51 } | |
52 | |
53 /* */ | |
54 #endif /* !ENABLE_SVR_REMOTETCPFWD */ | |
38 | 55 |
39 static void send_msg_request_success(); | 56 static void send_msg_request_success(); |
40 static void send_msg_request_failure(); | |
41 static int svr_cancelremotetcp(); | 57 static int svr_cancelremotetcp(); |
42 static int svr_remotetcpreq(); | 58 static int svr_remotetcpreq(); |
43 static int newtcpdirect(struct Channel * channel); | 59 static int newtcpdirect(struct Channel * channel); |
44 | 60 |
61 #ifdef ENABLE_SVR_REMOTETCPFWD | |
62 static const struct ChanType svr_chan_tcpremote = { | |
63 1, /* sepfds */ | |
64 "forwarded-tcpip", | |
65 NULL, | |
66 NULL, | |
67 NULL, | |
68 NULL | |
69 }; | |
70 | |
71 /* At the moment this is completely used for tcp code (with the name reflecting | |
72 * that). If new request types are added, this should be replaced with code | |
73 * similar to the request-switching in chansession.c */ | |
74 void recv_msg_global_request_remotetcp() { | |
75 | |
76 unsigned char* reqname = NULL; | |
77 unsigned int namelen; | |
78 unsigned int wantreply = 0; | |
79 int ret = DROPBEAR_FAILURE; | |
80 | |
81 TRACE(("enter recv_msg_global_request_remotetcp")) | |
82 | |
83 if (svr_opts.noremotetcp || !svr_pubkey_allows_tcpfwd()) { | |
84 TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled")) | |
85 goto out; | |
86 } | |
87 | |
88 reqname = buf_getstring(ses.payload, &namelen); | |
89 wantreply = buf_getbool(ses.payload); | |
90 | |
91 if (namelen > MAX_NAME_LEN) { | |
92 TRACE(("name len is wrong: %d", namelen)) | |
93 goto out; | |
94 } | |
95 | |
96 if (strcmp("tcpip-forward", reqname) == 0) { | |
97 ret = svr_remotetcpreq(); | |
98 } else if (strcmp("cancel-tcpip-forward", reqname) == 0) { | |
99 ret = svr_cancelremotetcp(); | |
100 } else { | |
101 TRACE(("reqname isn't tcpip-forward: '%s'", reqname)) | |
102 } | |
103 | |
104 out: | |
105 if (wantreply) { | |
106 if (ret == DROPBEAR_SUCCESS) { | |
107 send_msg_request_success(); | |
108 } else { | |
109 send_msg_request_failure(); | |
110 } | |
111 } | |
112 | |
113 m_free(reqname); | |
114 | |
115 TRACE(("leave recv_msg_global_request")) | |
116 } | |
117 | |
118 | |
119 static void send_msg_request_success() { | |
120 | |
121 CHECKCLEARTOWRITE(); | |
122 buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_SUCCESS); | |
123 encrypt_packet(); | |
124 | |
125 } | |
126 | |
127 static int matchtcp(void* typedata1, void* typedata2) { | |
128 | |
129 const struct TCPListener *info1 = (struct TCPListener*)typedata1; | |
130 const struct TCPListener *info2 = (struct TCPListener*)typedata2; | |
131 | |
132 return (info1->listenport == info2->listenport) | |
133 && (info1->chantype == info2->chantype) | |
134 && (strcmp(info1->listenaddr, info2->listenaddr) == 0); | |
135 } | |
136 | |
137 static int svr_cancelremotetcp() { | |
138 | |
139 int ret = DROPBEAR_FAILURE; | |
140 unsigned char * bindaddr = NULL; | |
141 unsigned int addrlen; | |
142 unsigned int port; | |
143 struct Listener * listener = NULL; | |
144 struct TCPListener tcpinfo; | |
145 | |
146 TRACE(("enter cancelremotetcp")) | |
147 | |
148 bindaddr = buf_getstring(ses.payload, &addrlen); | |
149 if (addrlen > MAX_IP_LEN) { | |
150 TRACE(("addr len too long: %d", addrlen)) | |
151 goto out; | |
152 } | |
153 | |
154 port = buf_getint(ses.payload); | |
155 | |
156 tcpinfo.sendaddr = NULL; | |
157 tcpinfo.sendport = 0; | |
158 tcpinfo.listenaddr = bindaddr; | |
159 tcpinfo.listenport = port; | |
160 listener = get_listener(CHANNEL_ID_TCPFORWARDED, &tcpinfo, matchtcp); | |
161 if (listener) { | |
162 remove_listener( listener ); | |
163 ret = DROPBEAR_SUCCESS; | |
164 } | |
165 | |
166 out: | |
167 m_free(bindaddr); | |
168 TRACE(("leave cancelremotetcp")) | |
169 return ret; | |
170 } | |
171 | |
172 static int svr_remotetcpreq() { | |
173 | |
174 int ret = DROPBEAR_FAILURE; | |
175 unsigned char * bindaddr = NULL; | |
176 unsigned int addrlen; | |
177 struct TCPListener *tcpinfo = NULL; | |
178 unsigned int port; | |
179 | |
180 TRACE(("enter remotetcpreq")) | |
181 | |
182 bindaddr = buf_getstring(ses.payload, &addrlen); | |
183 if (addrlen > MAX_IP_LEN) { | |
184 TRACE(("addr len too long: %d", addrlen)) | |
185 goto out; | |
186 } | |
187 | |
188 port = buf_getint(ses.payload); | |
189 | |
190 if (port == 0) { | |
191 dropbear_log(LOG_INFO, "Server chosen tcpfwd ports are unsupported"); | |
192 goto out; | |
193 } | |
194 | |
195 if (port < 1 || port > 65535) { | |
196 TRACE(("invalid port: %d", port)) | |
197 goto out; | |
198 } | |
199 | |
200 if (!ses.allowprivport && port < IPPORT_RESERVED) { | |
201 TRACE(("can't assign port < 1024 for non-root")) | |
202 goto out; | |
203 } | |
204 | |
205 tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener)); | |
206 tcpinfo->sendaddr = NULL; | |
207 tcpinfo->sendport = 0; | |
208 tcpinfo->listenport = port; | |
209 tcpinfo->chantype = &svr_chan_tcpremote; | |
210 tcpinfo->tcp_type = forwarded; | |
211 | |
212 if (!opts.listen_fwd_all || (strcmp(bindaddr, "localhost") == 0) ) { | |
213 // NULL means "localhost only" | |
214 m_free(bindaddr); | |
215 bindaddr = NULL; | |
216 } | |
217 tcpinfo->listenaddr = bindaddr; | |
218 | |
219 ret = listen_tcpfwd(tcpinfo); | |
220 | |
221 out: | |
222 if (ret == DROPBEAR_FAILURE) { | |
223 /* we only free it if a listener wasn't created, since the listener | |
224 * has to remember it if it's to be cancelled */ | |
225 m_free(bindaddr); | |
226 m_free(tcpinfo); | |
227 } | |
228 TRACE(("leave remotetcpreq")) | |
229 return ret; | |
230 } | |
231 | |
232 #endif /* ENABLE_SVR_REMOTETCPFWD */ | |
233 | |
234 #ifdef ENABLE_SVR_LOCALTCPFWD | |
45 | 235 |
46 const struct ChanType svr_chan_tcpdirect = { | 236 const struct ChanType svr_chan_tcpdirect = { |
47 1, /* sepfds */ | 237 1, /* sepfds */ |
48 "direct-tcpip", | 238 "direct-tcpip", |
49 newtcpdirect, /* init */ | 239 newtcpdirect, /* init */ |
50 NULL, /* checkclose */ | 240 NULL, /* checkclose */ |
51 NULL, /* reqhandler */ | 241 NULL, /* reqhandler */ |
52 NULL /* closehandler */ | 242 NULL /* closehandler */ |
53 }; | 243 }; |
54 | 244 |
55 static const struct ChanType svr_chan_tcpremote = { | |
56 1, /* sepfds */ | |
57 "forwarded-tcpip", | |
58 NULL, | |
59 NULL, | |
60 NULL, | |
61 NULL | |
62 }; | |
63 | |
64 /* At the moment this is completely used for tcp code (with the name reflecting | |
65 * that). If new request types are added, this should be replaced with code | |
66 * similar to the request-switching in chansession.c */ | |
67 void recv_msg_global_request_remotetcp() { | |
68 | |
69 unsigned char* reqname = NULL; | |
70 unsigned int namelen; | |
71 unsigned int wantreply = 0; | |
72 int ret = DROPBEAR_FAILURE; | |
73 | |
74 TRACE(("enter recv_msg_global_request_remotetcp")) | |
75 | |
76 if (svr_opts.noremotetcp || !svr_pubkey_allows_tcpfwd()) { | |
77 TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled")) | |
78 goto out; | |
79 } | |
80 | |
81 reqname = buf_getstring(ses.payload, &namelen); | |
82 wantreply = buf_getbool(ses.payload); | |
83 | |
84 if (namelen > MAX_NAME_LEN) { | |
85 TRACE(("name len is wrong: %d", namelen)) | |
86 goto out; | |
87 } | |
88 | |
89 if (strcmp("tcpip-forward", reqname) == 0) { | |
90 ret = svr_remotetcpreq(); | |
91 } else if (strcmp("cancel-tcpip-forward", reqname) == 0) { | |
92 ret = svr_cancelremotetcp(); | |
93 } else { | |
94 TRACE(("reqname isn't tcpip-forward: '%s'", reqname)) | |
95 } | |
96 | |
97 out: | |
98 if (wantreply) { | |
99 if (ret == DROPBEAR_SUCCESS) { | |
100 send_msg_request_success(); | |
101 } else { | |
102 send_msg_request_failure(); | |
103 } | |
104 } | |
105 | |
106 m_free(reqname); | |
107 | |
108 TRACE(("leave recv_msg_global_request")) | |
109 } | |
110 | |
111 | |
112 static void send_msg_request_success() { | |
113 | |
114 CHECKCLEARTOWRITE(); | |
115 buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_SUCCESS); | |
116 encrypt_packet(); | |
117 | |
118 } | |
119 | |
120 static void send_msg_request_failure() { | |
121 | |
122 CHECKCLEARTOWRITE(); | |
123 buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE); | |
124 encrypt_packet(); | |
125 | |
126 } | |
127 | |
128 static int matchtcp(void* typedata1, void* typedata2) { | |
129 | |
130 const struct TCPListener *info1 = (struct TCPListener*)typedata1; | |
131 const struct TCPListener *info2 = (struct TCPListener*)typedata2; | |
132 | |
133 return (info1->listenport == info2->listenport) | |
134 && (info1->chantype == info2->chantype) | |
135 && (strcmp(info1->listenaddr, info2->listenaddr) == 0); | |
136 } | |
137 | |
138 static int svr_cancelremotetcp() { | |
139 | |
140 int ret = DROPBEAR_FAILURE; | |
141 unsigned char * bindaddr = NULL; | |
142 unsigned int addrlen; | |
143 unsigned int port; | |
144 struct Listener * listener = NULL; | |
145 struct TCPListener tcpinfo; | |
146 | |
147 TRACE(("enter cancelremotetcp")) | |
148 | |
149 bindaddr = buf_getstring(ses.payload, &addrlen); | |
150 if (addrlen > MAX_IP_LEN) { | |
151 TRACE(("addr len too long: %d", addrlen)) | |
152 goto out; | |
153 } | |
154 | |
155 port = buf_getint(ses.payload); | |
156 | |
157 tcpinfo.sendaddr = NULL; | |
158 tcpinfo.sendport = 0; | |
159 tcpinfo.listenaddr = bindaddr; | |
160 tcpinfo.listenport = port; | |
161 listener = get_listener(CHANNEL_ID_TCPFORWARDED, &tcpinfo, matchtcp); | |
162 if (listener) { | |
163 remove_listener( listener ); | |
164 ret = DROPBEAR_SUCCESS; | |
165 } | |
166 | |
167 out: | |
168 m_free(bindaddr); | |
169 TRACE(("leave cancelremotetcp")) | |
170 return ret; | |
171 } | |
172 | |
173 static int svr_remotetcpreq() { | |
174 | |
175 int ret = DROPBEAR_FAILURE; | |
176 unsigned char * bindaddr = NULL; | |
177 unsigned int addrlen; | |
178 struct TCPListener *tcpinfo = NULL; | |
179 unsigned int port; | |
180 | |
181 TRACE(("enter remotetcpreq")) | |
182 | |
183 bindaddr = buf_getstring(ses.payload, &addrlen); | |
184 if (addrlen > MAX_IP_LEN) { | |
185 TRACE(("addr len too long: %d", addrlen)) | |
186 goto out; | |
187 } | |
188 | |
189 port = buf_getint(ses.payload); | |
190 | |
191 if (port == 0) { | |
192 dropbear_log(LOG_INFO, "Server chosen tcpfwd ports are unsupported"); | |
193 goto out; | |
194 } | |
195 | |
196 if (port < 1 || port > 65535) { | |
197 TRACE(("invalid port: %d", port)) | |
198 goto out; | |
199 } | |
200 | |
201 if (!ses.allowprivport && port < IPPORT_RESERVED) { | |
202 TRACE(("can't assign port < 1024 for non-root")) | |
203 goto out; | |
204 } | |
205 | |
206 tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener)); | |
207 tcpinfo->sendaddr = NULL; | |
208 tcpinfo->sendport = 0; | |
209 tcpinfo->listenport = port; | |
210 tcpinfo->chantype = &svr_chan_tcpremote; | |
211 tcpinfo->tcp_type = forwarded; | |
212 | |
213 if (!opts.listen_fwd_all || (strcmp(bindaddr, "localhost") == 0) ) { | |
214 // NULL means "localhost only" | |
215 m_free(bindaddr); | |
216 bindaddr = NULL; | |
217 } | |
218 tcpinfo->listenaddr = bindaddr; | |
219 | |
220 ret = listen_tcpfwd(tcpinfo); | |
221 | |
222 out: | |
223 if (ret == DROPBEAR_FAILURE) { | |
224 /* we only free it if a listener wasn't created, since the listener | |
225 * has to remember it if it's to be cancelled */ | |
226 m_free(bindaddr); | |
227 m_free(tcpinfo); | |
228 } | |
229 TRACE(("leave remotetcpreq")) | |
230 return ret; | |
231 } | |
232 | |
233 /* Called upon creating a new direct tcp channel (ie we connect out to an | 245 /* Called upon creating a new direct tcp channel (ie we connect out to an |
234 * address */ | 246 * address */ |
235 static int newtcpdirect(struct Channel * channel) { | 247 static int newtcpdirect(struct Channel * channel) { |
236 | 248 |
237 unsigned char* desthost = NULL; | 249 unsigned char* desthost = NULL; |
292 m_free(orighost); | 304 m_free(orighost); |
293 TRACE(("leave newtcpdirect: err %d", err)) | 305 TRACE(("leave newtcpdirect: err %d", err)) |
294 return err; | 306 return err; |
295 } | 307 } |
296 | 308 |
297 #endif | 309 #endif /* ENABLE_SVR_LOCALTCPFWD */ |