1 /* $OpenBSD: roaming_common.c,v 1.7 2009/12/06 23:53:45 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
40 static size_t out_buf_size
= 0;
41 static char *out_buf
= NULL
;
42 static size_t out_start
;
43 static size_t out_last
;
45 static u_int64_t write_bytes
= 0;
46 static u_int64_t read_bytes
= 0;
48 int roaming_enabled
= 0;
49 int resume_in_progress
= 0;
54 int fd
= packet_get_connection_out();
56 socklen_t optvallen
= sizeof(optval
);
58 if (getsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &optval
, &optvallen
) != 0)
59 optval
= DEFAULT_ROAMBUF
;
66 int fd
= packet_get_connection_in();
68 socklen_t optvallen
= sizeof(optval
);
70 if (getsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, &optval
, &optvallen
) != 0)
71 optval
= DEFAULT_ROAMBUF
;
76 set_out_buffer_size(size_t size
)
79 * The buffer size can only be set once and the buffer will live
80 * as long as the session lives.
82 if (out_buf
== NULL
) {
84 out_buf
= xmalloc(size
);
97 add_recv_bytes(u_int64_t num
)
109 roam_set_bytes(u_int64_t sent
, u_int64_t recvd
)
116 buf_append(const char *buf
, size_t count
)
118 if (count
> out_buf_size
) {
119 buf
+= count
- out_buf_size
;
120 count
= out_buf_size
;
122 if (count
< out_buf_size
- out_last
) {
123 memcpy(out_buf
+ out_last
, buf
, count
);
124 if (out_start
> out_last
)
129 size_t chunk
= out_buf_size
- out_last
;
130 memcpy(out_buf
+ out_last
, buf
, chunk
);
131 memcpy(out_buf
, buf
+ chunk
, count
- chunk
);
132 out_last
= count
- chunk
;
133 out_start
= out_last
+ 1;
138 roaming_write(int fd
, const void *buf
, size_t count
, int *cont
)
142 ret
= write(fd
, buf
, count
);
143 if (ret
> 0 && !resume_in_progress
) {
145 if (out_buf_size
> 0)
146 buf_append(buf
, ret
);
148 debug3("Wrote %ld bytes for a total of %llu", (long)ret
,
149 (unsigned long long)write_bytes
);
150 if (out_buf_size
> 0 &&
151 (ret
== 0 || (ret
== -1 && errno
== EPIPE
))) {
152 if (wait_for_roaming_reconnect() != 0) {
164 roaming_read(int fd
, void *buf
, size_t count
, int *cont
)
166 ssize_t ret
= read(fd
, buf
, count
);
168 if (!resume_in_progress
) {
171 } else if (out_buf_size
> 0 &&
172 (ret
== 0 || (ret
== -1 && (errno
== ECONNRESET
173 || errno
== ECONNABORTED
|| errno
== ETIMEDOUT
174 || errno
== EHOSTUNREACH
)))) {
175 debug("roaming_read failed for %d ret=%ld errno=%d",
176 fd
, (long)ret
, errno
);
178 if (wait_for_roaming_reconnect() == 0)
185 roaming_atomicio(ssize_t(*f
)(int, void*, size_t), int fd
, void *buf
,
188 size_t ret
= atomicio(f
, fd
, buf
, count
);
190 if (f
== vwrite
&& ret
> 0 && !resume_in_progress
) {
192 } else if (f
== read
&& ret
> 0 && !resume_in_progress
) {
199 resend_bytes(int fd
, u_int64_t
*offset
)
201 size_t available
, needed
;
203 if (out_start
< out_last
)
204 available
= out_last
- out_start
;
206 available
= out_buf_size
;
207 needed
= write_bytes
- *offset
;
208 debug3("resend_bytes: resend %lu bytes from %llu",
209 (unsigned long)needed
, (unsigned long long)*offset
);
210 if (needed
> available
)
211 fatal("Needed to resend more data than in the cache");
212 if (out_last
< needed
) {
213 int chunkend
= needed
- out_last
;
214 atomicio(vwrite
, fd
, out_buf
+ out_buf_size
- chunkend
,
216 atomicio(vwrite
, fd
, out_buf
, out_last
);
218 atomicio(vwrite
, fd
, out_buf
+ (out_last
- needed
), needed
);
223 * Caclulate a new key after a reconnect
226 calculate_new_key(u_int64_t
*key
, u_int64_t cookie
, u_int64_t challenge
)
228 const EVP_MD
*md
= EVP_sha1();
230 char hash
[EVP_MAX_MD_SIZE
];
234 buffer_put_int64(&b
, *key
);
235 buffer_put_int64(&b
, cookie
);
236 buffer_put_int64(&b
, challenge
);
238 EVP_DigestInit(&ctx
, md
);
239 EVP_DigestUpdate(&ctx
, buffer_ptr(&b
), buffer_len(&b
));
240 EVP_DigestFinal(&ctx
, hash
, NULL
);
243 buffer_append(&b
, hash
, EVP_MD_size(md
));
244 *key
= buffer_get_int64(&b
);