1 /* $OpenBSD: roaming_common.c,v 1.12 2014/01/09 23:20:00 djm Exp $ */
3 * Copyright (c) 2004-2009 AppGate Network Security AB
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/types.h>
21 #include <sys/socket.h>
25 #ifdef HAVE_INTTYPES_H
41 static size_t out_buf_size
= 0;
42 static char *out_buf
= NULL
;
43 static size_t out_start
;
44 static size_t out_last
;
46 static u_int64_t write_bytes
= 0;
47 static u_int64_t read_bytes
= 0;
49 int roaming_enabled
= 0;
50 int resume_in_progress
= 0;
53 get_snd_buf_size(void)
55 int fd
= packet_get_connection_out();
57 socklen_t optvallen
= sizeof(optval
);
59 if (getsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &optval
, &optvallen
) != 0)
60 optval
= DEFAULT_ROAMBUF
;
65 get_recv_buf_size(void)
67 int fd
= packet_get_connection_in();
69 socklen_t optvallen
= sizeof(optval
);
71 if (getsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, &optval
, &optvallen
) != 0)
72 optval
= DEFAULT_ROAMBUF
;
77 set_out_buffer_size(size_t size
)
79 if (size
== 0 || size
> MAX_ROAMBUF
)
80 fatal("%s: bad buffer size %lu", __func__
, (u_long
)size
);
82 * The buffer size can only be set once and the buffer will live
83 * as long as the session lives.
85 if (out_buf
== NULL
) {
87 out_buf
= xmalloc(size
);
100 add_recv_bytes(u_int64_t num
)
112 roam_set_bytes(u_int64_t sent
, u_int64_t recvd
)
119 buf_append(const char *buf
, size_t count
)
121 if (count
> out_buf_size
) {
122 buf
+= count
- out_buf_size
;
123 count
= out_buf_size
;
125 if (count
< out_buf_size
- out_last
) {
126 memcpy(out_buf
+ out_last
, buf
, count
);
127 if (out_start
> out_last
)
132 size_t chunk
= out_buf_size
- out_last
;
133 memcpy(out_buf
+ out_last
, buf
, chunk
);
134 memcpy(out_buf
, buf
+ chunk
, count
- chunk
);
135 out_last
= count
- chunk
;
136 out_start
= out_last
+ 1;
141 roaming_write(int fd
, const void *buf
, size_t count
, int *cont
)
145 ret
= write(fd
, buf
, count
);
146 if (ret
> 0 && !resume_in_progress
) {
148 if (out_buf_size
> 0)
149 buf_append(buf
, ret
);
151 if (out_buf_size
> 0 &&
152 (ret
== 0 || (ret
== -1 && errno
== EPIPE
))) {
153 if (wait_for_roaming_reconnect() != 0) {
165 roaming_read(int fd
, void *buf
, size_t count
, int *cont
)
167 ssize_t ret
= read(fd
, buf
, count
);
169 if (!resume_in_progress
) {
172 } else if (out_buf_size
> 0 &&
173 (ret
== 0 || (ret
== -1 && (errno
== ECONNRESET
174 || errno
== ECONNABORTED
|| errno
== ETIMEDOUT
175 || errno
== EHOSTUNREACH
)))) {
176 debug("roaming_read failed for %d ret=%ld errno=%d",
177 fd
, (long)ret
, errno
);
179 if (wait_for_roaming_reconnect() == 0)
186 roaming_atomicio(ssize_t(*f
)(int, void*, size_t), int fd
, void *buf
,
189 size_t ret
= atomicio(f
, fd
, buf
, count
);
191 if (f
== vwrite
&& ret
> 0 && !resume_in_progress
) {
193 } else if (f
== read
&& ret
> 0 && !resume_in_progress
) {
200 resend_bytes(int fd
, u_int64_t
*offset
)
202 size_t available
, needed
;
204 if (out_start
< out_last
)
205 available
= out_last
- out_start
;
207 available
= out_buf_size
;
208 needed
= write_bytes
- *offset
;
209 debug3("resend_bytes: resend %lu bytes from %llu",
210 (unsigned long)needed
, (unsigned long long)*offset
);
211 if (needed
> available
)
212 fatal("Needed to resend more data than in the cache");
213 if (out_last
< needed
) {
214 int chunkend
= needed
- out_last
;
215 atomicio(vwrite
, fd
, out_buf
+ out_buf_size
- chunkend
,
217 atomicio(vwrite
, fd
, out_buf
, out_last
);
219 atomicio(vwrite
, fd
, out_buf
+ (out_last
- needed
), needed
);
224 * Caclulate a new key after a reconnect
227 calculate_new_key(u_int64_t
*key
, u_int64_t cookie
, u_int64_t challenge
)
229 u_char hash
[SSH_DIGEST_MAX_LENGTH
];
233 buffer_put_int64(&b
, *key
);
234 buffer_put_int64(&b
, cookie
);
235 buffer_put_int64(&b
, challenge
);
237 if (ssh_digest_buffer(SSH_DIGEST_SHA1
, &b
, hash
, sizeof(hash
)) != 0)
238 fatal("%s: digest_buffer failed", __func__
);
241 buffer_append(&b
, hash
, ssh_digest_bytes(SSH_DIGEST_SHA1
));
242 *key
= buffer_get_int64(&b
);