1 /*
2 * ProFTPD - mod_sftp traffic analysis protection
3 * Copyright (c) 2008-2016 TJ Saunders
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 *
19 * As a special exemption, TJ Saunders and other respective copyright holders
20 * give permission to link this program with OpenSSL, and distribute the
21 * resulting executable, without including the source code for OpenSSL in the
22 * source distribution.
23 */
24
25 #include "mod_sftp.h"
26 #include "ssh2.h"
27 #include "packet.h"
28 #include "msg.h"
29 #include "tap.h"
30 #include "interop.h"
31
32 extern module sftp_module;
33
34 static pool *tap_pool = NULL;
35 static int tap_timerno = -1;
36
37 static const char *trace_channel = "ssh2";
38
39 struct sftp_tap_policy {
40 const char *policy;
41
42 unsigned int chance_max;
43 unsigned int chance;
44 unsigned int min_datalen;
45 unsigned int max_datalen;
46
47 int check_interval;
48 unsigned long min_secs;
49 unsigned long max_secs;
50 };
51
52 static struct sftp_tap_policy tap_policies[] = {
53 { "none", 0, 0, 0, 0, 0, 0, 0 },
54 { "low", 1000, 0, 64, 256, 5, 15, 300 },
55 { "medium", 100, 0, 32, 768, 5, 10, 60 },
56 { "high", 10, 0, 16, 2048, 1, 5, 15 },
57 { "paranoid", 1, 0, 0, 0, 1, 1, 5 },
58 { "rogaway", 1, 0, 64, 256, 0, 0, 0 },
59 { NULL, 0, 0, 0, 0, 0, 0, 0 }
60 };
61
62 static struct sftp_tap_policy curr_policy = { NULL, 0, 0, 0, 0, 0, 0, 0 };
63
64 /* This only checks whether to TRY to send a TAP packet; it does not force
65 * a TAP packet to be sent. The request to send a TAP packet, if we try,
66 * is still subject to the 1-in-N chance of sending a packet as set by
67 * the selected policy.
68 */
check_packet_times_cb(CALLBACK_FRAME)69 static int check_packet_times_cb(CALLBACK_FRAME) {
70 time_t last_recvd, last_sent, now;
71 unsigned long since_recvd, since_sent;
72 unsigned int chance;
73 int rnd;
74
75 /* Always return 1 so that this timer is rescheduled. */
76
77 sftp_ssh2_packet_get_last_recvd(&last_recvd);
78 sftp_ssh2_packet_get_last_sent(&last_sent);
79 time(&now);
80
81 since_recvd = now - last_recvd;
82 since_sent = now - last_sent;
83
84 /* If it's been less than min_secs, do NOT send a packet. */
85 if (since_recvd <= curr_policy.min_secs &&
86 since_sent <= curr_policy.max_secs) {
87 return 1;
88 }
89
90 /* If it's been more than max_secs, DO attempt send a packet. */
91 if (since_recvd >= curr_policy.max_secs &&
92 since_sent >= curr_policy.max_secs) {
93 pr_trace_msg(trace_channel, 15, "too much inactivity, attempting "
94 "to send TAP packet");
95
96 if (sftp_tap_send_packet() < 0) {
97 pr_trace_msg(trace_channel, 3, "error sending TAP packet: %s",
98 strerror(errno));
99 }
100
101 return 1;
102 }
103
104 /* Otherwise, pick a random number, see if it's time to send a packet. */
105 if (curr_policy.chance_max != 1) {
106 rnd = (int) (rand() / (RAND_MAX / curr_policy.chance_max + 1));
107
108 } else {
109 rnd = 1;
110 }
111
112 chance = rnd;
113 if (chance == curr_policy.chance) {
114 pr_trace_msg(trace_channel, 15, "perhaps too inactive, attempting to send "
115 "a TAP packet");
116
117 if (sftp_tap_send_packet() < 0) {
118 pr_trace_msg(trace_channel, 3, "error sending TAP packet: %s",
119 strerror(errno));
120 }
121
122 return 1;
123 }
124
125 return 1;
126 }
127
copy_policy(struct sftp_tap_policy * dst,struct sftp_tap_policy * src)128 static void copy_policy(struct sftp_tap_policy *dst,
129 struct sftp_tap_policy *src) {
130
131 dst->policy = src->policy;
132 dst->chance_max = src->chance_max;
133 dst->min_datalen = src->min_datalen;
134 dst->max_datalen = src->max_datalen;
135 }
136
set_policy_chance(struct sftp_tap_policy * policy)137 static void set_policy_chance(struct sftp_tap_policy *policy) {
138 if (policy->chance_max == 0) {
139 /* This is the 'none' policy; no need to do anything. */
140 return;
141 }
142
143 if (policy->chance_max != 1) {
144 policy->chance = (int) (rand() / (RAND_MAX / policy->chance_max + 1));
145
146 } else {
147 policy->chance = 1;
148 }
149 }
150
set_policy_timer(struct sftp_tap_policy * policy)151 static void set_policy_timer(struct sftp_tap_policy *policy) {
152
153 /* Start a timer which checks the last times we received and sent packets.
154 * From there, we may want to inject a TAP message, depending on the
155 * policy.
156 */
157 if (policy->check_interval > 0) {
158 tap_timerno = pr_timer_add(policy->check_interval, -1,
159 &sftp_module, check_packet_times_cb, "SFTP TAP check");
160 }
161 }
162
sftp_tap_have_policy(const char * policy)163 int sftp_tap_have_policy(const char *policy) {
164 register unsigned int i;
165
166 for (i = 0; tap_policies[i].policy; i++) {
167 if (strcasecmp(tap_policies[i].policy, policy) == 0) {
168 return 0;
169 }
170 }
171
172 errno = ENOENT;
173 return -1;
174 }
175
sftp_tap_send_packet(void)176 int sftp_tap_send_packet(void) {
177 int rnd;
178 unsigned int chance;
179
180 if (!sftp_interop_supports_feature(SFTP_SSH2_FEAT_IGNORE_MSG)) {
181 pr_trace_msg(trace_channel, 3,
182 "unable to send TAP packet: IGNORE not supported by client");
183 return 0;
184 }
185
186 if (curr_policy.chance_max == 0) {
187 /* The "none" policy is in effect; nothing to do. */
188 return 0;
189 }
190
191 /* Calculate our odds of sending a tap packet, based on the configured
192 * policy.
193 */
194 if (curr_policy.chance_max != 1) {
195 rnd = (int) (rand() / (RAND_MAX / curr_policy.chance_max + 1));
196
197 } else {
198 rnd = 1;
199 }
200
201 chance = rnd;
202 if (chance == curr_policy.chance) {
203 unsigned char *buf, *ptr, *rand_data;
204 uint32_t bufsz, buflen, rand_datalen;
205 struct ssh2_packet *pkt;
206 unsigned int max_datalen = 8192;
207
208 if (curr_policy.max_datalen) {
209 max_datalen = curr_policy.max_datalen;
210 }
211
212 rand_datalen = (uint32_t) (curr_policy.min_datalen + rand() /
213 (RAND_MAX / (max_datalen - curr_policy.min_datalen) + 1));
214
215 pr_trace_msg(trace_channel, 20, "sending random SSH2_MSG_IGNORE message "
216 "(%lu bytes) based on '%s' TAP policy", (unsigned long) rand_datalen,
217 curr_policy.policy);
218
219 pkt = sftp_ssh2_packet_create(tap_pool);
220 bufsz = buflen = rand_datalen + 32;
221 ptr = buf = palloc(pkt->pool, bufsz);
222
223 rand_data = palloc(pkt->pool, rand_datalen);
224
225 RAND_bytes(rand_data, rand_datalen);
226
227 sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_IGNORE);
228 sftp_msg_write_data(&buf, &buflen, rand_data, rand_datalen, TRUE);
229
230 pkt->payload = ptr;
231 pkt->payload_len = (bufsz - buflen);
232
233 if (sftp_ssh2_packet_send(sftp_conn->wfd, pkt) < 0) {
234 int xerrno = errno;
235
236 pr_trace_msg(trace_channel, 12,
237 "error writing TAP packet: %s", strerror(xerrno));
238 }
239
240 destroy_pool(pkt->pool);
241 }
242
243 return 0;
244 }
245
sftp_tap_set_policy(const char * policy)246 int sftp_tap_set_policy(const char *policy) {
247 register unsigned int i;
248
249 if (tap_pool) {
250
251 /* Special case: IFF the existing policy is 'none' AND the given
252 * policy is 'rogaway', just return. The 'none' policy must have been
253 * explicitly configured, and it should override the automatic use of
254 * the 'rogaway' policy.
255 */
256 if (strncmp(curr_policy.policy, "none", 5) == 0 &&
257 strncasecmp(policy, "rogaway", 8) == 0) {
258 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
259 "'none' traffic policy explicitly configured, ignoring '%s' policy",
260 policy);
261 return 0;
262 }
263
264 destroy_pool(tap_pool);
265
266 if (tap_timerno > 0) {
267 pr_timer_remove(tap_timerno, &sftp_module);
268 tap_timerno = -1;
269 }
270 }
271
272 tap_pool = make_sub_pool(sftp_pool);
273 pr_pool_tag(tap_pool, "SFTP TAP Pool");
274
275 memset(&curr_policy, 0, sizeof(struct sftp_tap_policy));
276
277 for (i = 0; tap_policies[i].policy; i++) {
278 if (strcasecmp(tap_policies[i].policy, policy) == 0) {
279 copy_policy(&curr_policy, &(tap_policies[i]));
280 set_policy_chance(&curr_policy);
281 set_policy_timer(&curr_policy);
282 return 0;
283 }
284 }
285
286 errno = ENOENT;
287 return -1;
288 }
289