Branch data Line data Source code
1 : : #include <netinet/tcp.h>
2 : : #include <sys/ioctl.h>
3 : : #include <linux/sockios.h>
4 : : #include <unistd.h>
5 : : #include <stdlib.h>
6 : : #include <sys/mman.h>
7 : : #include <string.h>
8 : :
9 : : #include "crtools.h"
10 : : #include "util.h"
11 : : #include "list.h"
12 : : #include "log.h"
13 : : #include "types.h"
14 : : #include "files.h"
15 : : #include "sockets.h"
16 : : #include "files.h"
17 : : #include "sk-inet.h"
18 : : #include "netfilter.h"
19 : : #include "image.h"
20 : :
21 : : #include "protobuf.h"
22 : : #include "protobuf/tcp-stream.pb-c.h"
23 : :
24 : : struct tcp_repair_opt {
25 : : u32 opt_code;
26 : : u32 opt_val;
27 : : };
28 : :
29 : : enum {
30 : : TCP_NO_QUEUE,
31 : : TCP_RECV_QUEUE,
32 : : TCP_SEND_QUEUE,
33 : : TCP_QUEUES_NR,
34 : : };
35 : :
36 : : #ifndef TCPOPT_SACK_PERM
37 : : #define TCPOPT_SACK_PERM TCPOPT_SACK_PERMITTED
38 : : #endif
39 : :
40 : : static LIST_HEAD(cpt_tcp_repair_sockets);
41 : : static LIST_HEAD(rst_tcp_repair_sockets);
42 : :
43 : 17 : static int tcp_repair_on(int fd)
44 : : {
45 : 17 : int ret, aux = 1;
46 : :
47 : 17 : ret = setsockopt(fd, SOL_TCP, TCP_REPAIR, &aux, sizeof(aux));
48 [ - + ]: 17 : if (ret < 0)
49 : 0 : pr_perror("Can't turn TCP repair mode ON");
50 : :
51 : 17 : return ret;
52 : : }
53 : :
54 : 8 : static int refresh_inet_sk(struct inet_sk_desc *sk)
55 : : {
56 : : int size;
57 : : struct tcp_info info;
58 : :
59 [ - + ]: 8 : if (dump_opt(sk->rfd, SOL_TCP, TCP_INFO, &info)) {
60 : 0 : pr_perror("Failt to obtain TCP_INFO");
61 : : return -1;
62 : : }
63 : :
64 [ - + ]: 8 : switch (info.tcpi_state) {
65 : : case TCP_ESTABLISHED:
66 : : case TCP_CLOSE:
67 : : break;
68 : : default:
69 : 0 : pr_err("Unknown state %d\n", sk->state);
70 : : return -1;
71 : : }
72 : :
73 [ - + ]: 8 : if (ioctl(sk->rfd, SIOCOUTQ, &size) == -1) {
74 : 0 : pr_perror("Unable to get size of snd queue");
75 : : return -1;
76 : : }
77 : :
78 : 8 : sk->wqlen = size;
79 : :
80 [ - + ]: 8 : if (ioctl(sk->rfd, SIOCINQ, &size) == -1) {
81 : 0 : pr_perror("Unable to get size of recv queue");
82 : : return -1;
83 : : }
84 : :
85 : 8 : sk->rqlen = size;
86 : :
87 : : return 0;
88 : : }
89 : :
90 : 8 : static int tcp_repair_establised(int fd, struct inet_sk_desc *sk)
91 : : {
92 : : int ret;
93 : :
94 : 8 : pr_info("\tTurning repair on for socket %x\n", sk->sd.ino);
95 : : /*
96 : : * Keep the socket open in crtools till the very end. In
97 : : * case we close this fd after one task fd dumping and
98 : : * fail we'll have to turn repair mode off
99 : : */
100 : 8 : sk->rfd = dup(fd);
101 [ - + ]: 8 : if (sk->rfd < 0) {
102 : 0 : pr_perror("Can't save socket fd for repair");
103 : 0 : goto err1;
104 : : }
105 : :
106 [ + - ]: 8 : if (!(opts.namespaces_flags & CLONE_NEWNET)) {
107 : 8 : ret = nf_lock_connection(sk);
108 [ + - ]: 8 : if (ret < 0)
109 : : goto err2;
110 : : }
111 : :
112 : 8 : ret = tcp_repair_on(sk->rfd);
113 [ + - ]: 8 : if (ret < 0)
114 : : goto err3;
115 : :
116 : 8 : list_add_tail(&sk->rlist, &cpt_tcp_repair_sockets);
117 : :
118 : 8 : ret = refresh_inet_sk(sk);
119 [ - + ]: 8 : if (ret < 0)
120 : : goto err1;
121 : :
122 : : return 0;
123 : :
124 : : err3:
125 [ # # ]: 0 : if (!(opts.namespaces_flags & CLONE_NEWNET))
126 : 0 : nf_unlock_connection(sk);
127 : : err2:
128 : 8 : close(sk->rfd);
129 : : err1:
130 : : return -1;
131 : : }
132 : :
133 : 0 : static void tcp_unlock_one(struct inet_sk_desc *sk)
134 : : {
135 : : int ret;
136 : :
137 : 0 : list_del(&sk->rlist);
138 : :
139 : 0 : ret = nf_unlock_connection(sk);
140 [ # # ]: 0 : if (ret < 0)
141 : 0 : pr_perror("Failed to unlock TCP connection");
142 : :
143 : 0 : tcp_repair_off(sk->rfd);
144 : 0 : close(sk->rfd);
145 : 0 : }
146 : :
147 : 90 : void cpt_unlock_tcp_connections(void)
148 : : {
149 : : struct inet_sk_desc *sk, *n;
150 : :
151 [ - + ]: 90 : list_for_each_entry_safe(sk, n, &cpt_tcp_repair_sockets, rlist)
152 : 0 : tcp_unlock_one(sk);
153 : 90 : }
154 : :
155 : : /*
156 : : * TCP queues sequences and their relations to the code below
157 : : *
158 : : * output queue
159 : : * net <----------------------------- sk
160 : : * ^ ^ ^ seq >>
161 : : * snd_una snd_nxt write_seq
162 : : *
163 : : * input queue
164 : : * net -----------------------------> sk
165 : : * << seq ^ ^
166 : : * rcv_nxt copied_seq
167 : : *
168 : : *
169 : : * inq_len = rcv_nxt - copied_seq = SIOCINQ
170 : : * outq_len = write_seq - snd_una = SIOCOUTQ
171 : : * inq_seq = rcv_nxt
172 : : * outq_seq = write_seq
173 : : *
174 : : * On restore kernel moves the option we configure with setsockopt,
175 : : * thus we should advance them on the _len value in restore_tcp_seqs.
176 : : *
177 : : */
178 : :
179 : 16 : static int tcp_stream_get_queue(int sk, int queue_id,
180 : : u32 *seq, u32 len, char **bufp)
181 : : {
182 : : int ret, aux;
183 : : socklen_t auxl;
184 : : char *buf;
185 : :
186 : 16 : pr_debug("\tSet repair queue %d\n", queue_id);
187 : 16 : aux = queue_id;
188 : 16 : auxl = sizeof(aux);
189 : 16 : ret = setsockopt(sk, SOL_TCP, TCP_REPAIR_QUEUE, &aux, auxl);
190 [ + - ]: 16 : if (ret < 0)
191 : : goto err_sopt;
192 : :
193 : 16 : pr_debug("\tGet queue seq\n");
194 : 16 : auxl = sizeof(*seq);
195 : 16 : ret = getsockopt(sk, SOL_TCP, TCP_QUEUE_SEQ, seq, &auxl);
196 [ + - ]: 16 : if (ret < 0)
197 : : goto err_sopt;
198 : :
199 : 16 : pr_info("\t`- seq %u len %u\n", *seq, len);
200 : :
201 [ + + ]: 16 : if (len) {
202 : : /*
203 : : * Try to grab one byte more from the queue to
204 : : * make sure there are len bytes for real
205 : : */
206 [ - + ]: 5 : buf = xmalloc(len + 1);
207 [ + - ]: 5 : if (!buf)
208 : : goto err_buf;
209 : :
210 : 5 : pr_debug("\tReading queue (%d bytes)\n", len);
211 : 5 : ret = recv(sk, buf, len + 1, MSG_PEEK | MSG_DONTWAIT);
212 [ + - ]: 5 : if (ret != len)
213 : : goto err_recv;
214 : : } else
215 : : buf = NULL;
216 : :
217 : 16 : *bufp = buf;
218 : : return 0;
219 : :
220 : : err_sopt:
221 : 0 : pr_perror("\tsockopt failed");
222 : : err_buf:
223 : : return -1;
224 : :
225 : : err_recv:
226 : 0 : pr_perror("\trecv failed (%d, want %d, errno %d)", ret, len, errno);
227 [ # # ]: 16 : xfree(buf);
228 : : goto err_buf;
229 : : }
230 : :
231 : 8 : static int tcp_stream_get_options(int sk, TcpStreamEntry *tse)
232 : : {
233 : : int ret;
234 : : socklen_t auxl;
235 : : struct tcp_info ti;
236 : :
237 : 8 : auxl = sizeof(ti);
238 : 8 : ret = getsockopt(sk, SOL_TCP, TCP_INFO, &ti, &auxl);
239 [ + - ]: 8 : if (ret < 0)
240 : : goto err_sopt;
241 : :
242 : 8 : auxl = sizeof(tse->mss_clamp);
243 : 8 : ret = getsockopt(sk, SOL_TCP, TCP_MAXSEG, &tse->mss_clamp, &auxl);
244 [ + - ]: 8 : if (ret < 0)
245 : : goto err_sopt;
246 : :
247 : 8 : tse->opt_mask = ti.tcpi_options;
248 [ + - ]: 8 : if (ti.tcpi_options & TCPI_OPT_WSCALE) {
249 : 8 : tse->snd_wscale = ti.tcpi_snd_wscale;
250 : 8 : tse->rcv_wscale = ti.tcpi_rcv_wscale;
251 : 8 : tse->has_rcv_wscale = true;
252 : : }
253 : :
254 [ + - ]: 8 : pr_info("\toptions: mss_clamp %x wscale %x tstamp %d sack %d\n",
255 : : (int)tse->mss_clamp,
256 : : ti.tcpi_options & TCPI_OPT_WSCALE ? (int)tse->snd_wscale : -1,
257 : : ti.tcpi_options & TCPI_OPT_TIMESTAMPS ? 1 : 0,
258 : : ti.tcpi_options & TCPI_OPT_SACK ? 1 : 0);
259 : :
260 : : return 0;
261 : :
262 : : err_sopt:
263 : 8 : pr_perror("\tsockopt failed");
264 : : return -1;
265 : : }
266 : :
267 : 8 : static int dump_tcp_conn_state(struct inet_sk_desc *sk)
268 : : {
269 : : int ret, img_fd;
270 : 8 : TcpStreamEntry tse = TCP_STREAM_ENTRY__INIT;
271 : : char *in_buf, *out_buf;
272 : :
273 : : /*
274 : : * Read queue
275 : : */
276 : :
277 : 8 : pr_info("Reading inq for socket\n");
278 : 8 : tse.inq_len = sk->rqlen;
279 : 8 : ret = tcp_stream_get_queue(sk->rfd, TCP_RECV_QUEUE,
280 : : &tse.inq_seq, tse.inq_len, &in_buf);
281 [ + - ]: 8 : if (ret < 0)
282 : : goto err_in;
283 : :
284 : : /*
285 : : * Write queue
286 : : */
287 : :
288 : 8 : pr_info("Reading outq for socket\n");
289 : 8 : tse.outq_len = sk->wqlen;
290 : 8 : ret = tcp_stream_get_queue(sk->rfd, TCP_SEND_QUEUE,
291 : : &tse.outq_seq, tse.outq_len, &out_buf);
292 [ + - ]: 8 : if (ret < 0)
293 : : goto err_out;
294 : :
295 : : /*
296 : : * Initial options
297 : : */
298 : :
299 : 8 : pr_info("Reasing options for socket\n");
300 : 8 : ret = tcp_stream_get_options(sk->rfd, &tse);
301 [ + - ]: 8 : if (ret < 0)
302 : : goto err_opt;
303 : :
304 : : /*
305 : : * Push the stuff to image
306 : : */
307 : :
308 : 8 : img_fd = open_image(CR_FD_TCP_STREAM, O_DUMP, sk->sd.ino);
309 [ + - ]: 8 : if (img_fd < 0)
310 : : goto err_img;
311 : :
312 : 8 : ret = pb_write_one(img_fd, &tse, PB_TCP_STREAM);
313 [ + - ]: 8 : if (ret < 0)
314 : : goto err_iw;
315 : :
316 [ + + ]: 8 : if (in_buf) {
317 : 3 : ret = write_img_buf(img_fd, in_buf, tse.inq_len);
318 [ + - ]: 3 : if (ret < 0)
319 : : goto err_iw;
320 : : }
321 : :
322 [ + + ]: 8 : if (out_buf) {
323 : 2 : ret = write_img_buf(img_fd, out_buf, tse.outq_len);
324 [ + - ]: 2 : if (ret < 0)
325 : : goto err_iw;
326 : : }
327 : :
328 : 8 : pr_info("Done\n");
329 : : err_iw:
330 : 8 : close(img_fd);
331 : : err_img:
332 : : err_opt:
333 [ + + ]: 8 : xfree(out_buf);
334 : : err_out:
335 [ + + ]: 8 : xfree(in_buf);
336 : : err_in:
337 : 8 : return ret;
338 : : }
339 : :
340 : 24 : int dump_one_tcp(int fd, struct inet_sk_desc *sk)
341 : : {
342 [ + + ]: 24 : if (sk->state != TCP_ESTABLISHED)
343 : : return 0;
344 : :
345 : 8 : pr_info("Dumping TCP connection\n");
346 : :
347 [ + - ]: 8 : if (tcp_repair_establised(fd, sk))
348 : : return -1;
349 : :
350 [ + - ]: 8 : if (dump_tcp_conn_state(sk))
351 : : return -1;
352 : :
353 : : /*
354 : : * Socket is left in repair mode, so that at the end it's just
355 : : * closed and the connection is silently terminated
356 : : */
357 : 24 : return 0;
358 : : }
359 : :
360 : 16 : static int set_tcp_queue_seq(int sk, int queue, u32 seq)
361 : : {
362 : 16 : pr_debug("\tSetting %d queue seq to %u\n", queue, seq);
363 : :
364 [ - + ]: 16 : if (setsockopt(sk, SOL_TCP, TCP_REPAIR_QUEUE, &queue, sizeof(queue)) < 0) {
365 : 0 : pr_perror("Can't set repair queue");
366 : 0 : return -1;
367 : : }
368 : :
369 [ - + ]: 16 : if (setsockopt(sk, SOL_TCP, TCP_QUEUE_SEQ, &seq, sizeof(seq)) < 0) {
370 : 0 : pr_perror("Can't set queue seq");
371 : 16 : return -1;
372 : : }
373 : :
374 : : return 0;
375 : : }
376 : :
377 : 8 : static int restore_tcp_seqs(int sk, TcpStreamEntry *tse)
378 : : {
379 [ + - ]: 8 : if (set_tcp_queue_seq(sk, TCP_RECV_QUEUE,
380 : 8 : tse->inq_seq - tse->inq_len))
381 : : return -1;
382 [ + - ]: 8 : if (set_tcp_queue_seq(sk, TCP_SEND_QUEUE,
383 : 8 : tse->outq_seq - tse->outq_len))
384 : : return -1;
385 : :
386 : 8 : return 0;
387 : : }
388 : :
389 : 5 : static int send_tcp_queue(int sk, int queue, u32 len, int imgfd)
390 : : {
391 : : int ret;
392 : : char *buf;
393 : :
394 : 5 : pr_debug("\tRestoring TCP %d queue data %u bytes\n", queue, len);
395 : :
396 [ - + ]: 5 : if (setsockopt(sk, SOL_TCP, TCP_REPAIR_QUEUE, &queue, sizeof(queue)) < 0) {
397 : 0 : pr_perror("Can't set repair queue");
398 : 0 : return -1;
399 : : }
400 : :
401 [ - + ]: 5 : buf = xmalloc(len);
402 [ + - ]: 5 : if (!buf)
403 : : return -1;
404 : :
405 [ + - ]: 5 : if (read_img_buf(imgfd, buf, len) < 0)
406 : : return -1;
407 : :
408 : 5 : ret = send(sk, buf, len, 0);
409 : :
410 [ + - ]: 5 : xfree(buf);
411 : :
412 [ - + ]: 5 : if (ret != len) {
413 : 0 : pr_perror("Can't restore %d queue data (%d), want %d",
414 : : queue, ret, len);
415 : 5 : return -1;
416 : : }
417 : :
418 : : return 0;
419 : : }
420 : :
421 : 8 : static int restore_tcp_queues(int sk, TcpStreamEntry *tse, int fd)
422 : : {
423 [ + - ]: 8 : if (restore_prepare_socket(sk))
424 : : return -1;
425 : :
426 [ + + + - ]: 11 : if (tse->inq_len &&
427 : 3 : send_tcp_queue(sk, TCP_RECV_QUEUE, tse->inq_len, fd))
428 : : return -1;
429 [ + + + - ]: 10 : if (tse->outq_len &&
430 : 2 : send_tcp_queue(sk, TCP_SEND_QUEUE, tse->outq_len, fd))
431 : : return -1;
432 : :
433 : : return 0;
434 : : }
435 : :
436 : 8 : static int restore_tcp_opts(int sk, TcpStreamEntry *tse)
437 : : {
438 : : struct tcp_repair_opt opts[4];
439 : 8 : int onr = 0;
440 : :
441 : 8 : pr_debug("\tRestoring TCP options\n");
442 : :
443 [ + - ]: 8 : if (tse->opt_mask & TCPI_OPT_SACK) {
444 : 8 : pr_debug("\t\tWill turn SAK on\n");
445 : 8 : opts[onr].opt_code = TCPOPT_SACK_PERM;
446 : 8 : opts[onr].opt_val = 0;
447 : 8 : onr++;
448 : : }
449 : :
450 [ + - ]: 8 : if (tse->opt_mask & TCPI_OPT_WSCALE) {
451 : 8 : pr_debug("\t\tWill set snd_wscale to %u\n", tse->snd_wscale);
452 : 8 : pr_debug("\t\tWill set rcv_wscale to %u\n", tse->rcv_wscale);
453 : 8 : opts[onr].opt_code = TCPOPT_WINDOW;
454 : 8 : opts[onr].opt_val = tse->snd_wscale + (tse->rcv_wscale << 16);
455 : 8 : onr++;
456 : : }
457 : :
458 [ + - ]: 8 : if (tse->opt_mask & TCPI_OPT_TIMESTAMPS) {
459 : 8 : pr_debug("\t\tWill turn timestamps on\n");
460 : 8 : opts[onr].opt_code = TCPOPT_TIMESTAMP;
461 : 8 : opts[onr].opt_val = 0;
462 : 8 : onr++;
463 : : }
464 : :
465 : 8 : pr_debug("Will set mss clamp to %u\n", tse->mss_clamp);
466 : 8 : opts[onr].opt_code = TCPOPT_MAXSEG;
467 : 8 : opts[onr].opt_val = tse->mss_clamp;
468 : 8 : onr++;
469 : :
470 [ - + ]: 8 : if (setsockopt(sk, SOL_TCP, TCP_REPAIR_OPTIONS,
471 : : opts, onr * sizeof(struct tcp_repair_opt)) < 0) {
472 : 8 : pr_perror("Can't repair options");
473 : : return -1;
474 : : }
475 : :
476 : : return 0;
477 : : }
478 : :
479 : 8 : static int restore_tcp_conn_state(int sk, struct inet_sk_info *ii)
480 : : {
481 : : int ifd;
482 : : TcpStreamEntry *tse;
483 : :
484 : 8 : pr_info("Restoring TCP connection id %x ino %x\n", ii->ie->id, ii->ie->ino);
485 : :
486 : 8 : ifd = open_image_ro(CR_FD_TCP_STREAM, ii->ie->ino);
487 [ + - ]: 8 : if (ifd < 0)
488 : : goto err;
489 : :
490 [ + - ]: 8 : if (pb_read_one(ifd, &tse, PB_TCP_STREAM) < 0)
491 : : goto err_c;
492 : :
493 [ + - ]: 8 : if (restore_tcp_seqs(sk, tse))
494 : : goto err_c;
495 : :
496 [ + - ]: 8 : if (inet_bind(sk, ii))
497 : : goto err_c;
498 : :
499 [ + - ]: 8 : if (inet_connect(sk, ii))
500 : : goto err_c;
501 : :
502 [ + - ]: 8 : if (restore_tcp_opts(sk, tse))
503 : : goto err_c;
504 : :
505 [ + - ]: 8 : if (restore_tcp_queues(sk, tse, ifd))
506 : : goto err_c;
507 : :
508 : 8 : tcp_stream_entry__free_unpacked(tse, NULL);
509 : 8 : close(ifd);
510 : : return 0;
511 : :
512 : : err_c:
513 : 0 : tcp_stream_entry__free_unpacked(tse, NULL);
514 : 8 : close(ifd);
515 : : err:
516 : : return -1;
517 : : }
518 : :
519 : : /*
520 : : * rst_tcp_socks contains sockets in repair mode,
521 : : * which will be off in restorer before resuming.
522 : : */
523 : : static int *rst_tcp_socks = NULL;
524 : : static int rst_tcp_socks_num = 0;
525 : : int rst_tcp_socks_size = 0;
526 : :
527 : 349 : int rst_tcp_socks_remap(void *addr)
528 : : {
529 : : void *ret;
530 [ + + ]: 349 : if (!rst_tcp_socks) {
531 [ - + ]: 343 : BUG_ON(rst_tcp_socks_size);
532 : : return 0;
533 : : }
534 : :
535 : 6 : rst_tcp_socks[rst_tcp_socks_num] = -1;
536 : :
537 : 6 : ret = mmap(addr, rst_tcp_socks_size, PROT_READ | PROT_WRITE,
538 : : MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
539 : :
540 [ - + ]: 6 : if (ret != addr) {
541 : 0 : pr_perror("mmap() failed\n");
542 : 0 : return -1;
543 : : }
544 : :
545 : 6 : memcpy(addr, rst_tcp_socks, rst_tcp_socks_size);
546 : :
547 : 349 : return 0;
548 : : }
549 : :
550 : 8 : static int rst_tcp_socks_add(int fd)
551 : : {
552 : : /* + 2 = ( new one + guard (-1) ) */
553 [ + + ]: 8 : if ((rst_tcp_socks_num + 2) * sizeof(int) > rst_tcp_socks_size) {
554 : 6 : rst_tcp_socks_size += PAGE_SIZE;
555 [ - + ]: 6 : rst_tcp_socks = xrealloc(rst_tcp_socks, rst_tcp_socks_size);
556 [ + - ]: 6 : if (rst_tcp_socks == NULL)
557 : : return -1;
558 : : }
559 : :
560 : 8 : rst_tcp_socks[rst_tcp_socks_num++] = fd;
561 : 8 : return 0;
562 : : }
563 : :
564 : 8 : int restore_one_tcp(int fd, struct inet_sk_info *ii)
565 : : {
566 : 8 : pr_info("Restoring TCP connection\n");
567 : :
568 [ + - ]: 8 : if (tcp_repair_on(fd))
569 : : return -1;
570 : :
571 [ + - ]: 8 : if (rst_tcp_socks_add(fd))
572 : : return -1;
573 : :
574 [ + - ]: 8 : if (restore_tcp_conn_state(fd, ii))
575 : : return -1;
576 : :
577 : 8 : return 0;
578 : : }
579 : :
580 : 16 : void tcp_locked_conn_add(struct inet_sk_info *ii)
581 : : {
582 : 16 : list_add_tail(&ii->rlist, &rst_tcp_repair_sockets);
583 : 16 : }
584 : :
585 : 90 : void rst_unlock_tcp_connections(void)
586 : : {
587 : : struct inet_sk_info *ii;
588 : :
589 [ + + ]: 98 : list_for_each_entry(ii, &rst_tcp_repair_sockets, rlist)
590 : 8 : nf_unlock_connection_info(ii);
591 : 90 : }
592 : :
593 : 0 : void show_tcp_stream(int fd, struct cr_options *opt)
594 : : {
595 : : TcpStreamEntry *tse;
596 : 0 : pr_img_head(CR_FD_TCP_STREAM);
597 : :
598 [ # # ]: 0 : if (pb_read_one_eof(fd, &tse, PB_TCP_STREAM) > 0) {
599 : 0 : pr_msg("IN: seq %10u len %10u\n", tse->inq_seq, tse->inq_len);
600 : 0 : pr_msg("OUT: seq %10u len %10u\n", tse->outq_seq, tse->outq_len);
601 : 0 : pr_msg("OPTS: %#x\n", (int)tse->opt_mask);
602 : 0 : pr_msg("\tmss_clamp %u\n", (int)tse->mss_clamp);
603 [ # # ]: 0 : if (tse->opt_mask & TCPI_OPT_WSCALE)
604 : 0 : pr_msg("\tsnd wscale %u\n", (int)tse->snd_wscale);
605 : 0 : pr_msg("\trcv wscale %u\n", (int)tse->rcv_wscale);
606 [ # # ]: 0 : if (tse->opt_mask & TCPI_OPT_TIMESTAMPS)
607 : 0 : pr_msg("\ttimestamps\n");
608 [ # # ]: 0 : if (tse->opt_mask & TCPI_OPT_SACK)
609 : 0 : pr_msg("\tsack\n");
610 : :
611 [ # # ]: 0 : if (opt->show_pages_content) {
612 : : unsigned char *buf;
613 : :
614 [ # # ]: 0 : buf = xmalloc(max(tse->inq_len, tse->outq_len));
615 [ # # ]: 0 : if (!buf)
616 : : goto out;
617 : :
618 [ # # ][ # # ]: 0 : if (tse->inq_len && read_img_buf(fd,
619 : : buf, tse->inq_len) > 0) {
620 : 0 : pr_msg("IN queue:\n");
621 : 0 : print_data(0, buf, tse->inq_len);
622 : : }
623 : :
624 [ # # ][ # # ]: 0 : if (tse->outq_len && read_img_buf(fd,
625 : : buf, tse->outq_len) > 0) {
626 : 0 : pr_msg("OUT queue:\n");
627 : 0 : print_data(0, buf, tse->outq_len);
628 : : }
629 : :
630 [ # # ]: 0 : xfree(buf);
631 : : }
632 : :
633 : 0 : tcp_stream_entry__free_unpacked(tse, NULL);
634 : 0 : tse = NULL;
635 : : }
636 : :
637 : : out:
638 [ # # ]: 0 : if (tse)
639 : 0 : tcp_stream_entry__free_unpacked(tse, NULL);
640 : 0 : pr_img_tail(CR_FD_TCP_STREAM);
641 : 0 : }
642 : :
643 : 1 : int check_tcp_repair(void)
644 : : {
645 : : int sk, ret;
646 : :
647 : 1 : sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
648 [ - + ]: 1 : if (sk < 0) {
649 : 0 : pr_perror("Can't create TCP socket :(\n");
650 : 0 : return -1;
651 : : }
652 : :
653 : 1 : ret = tcp_repair_on(sk);
654 : 1 : close(sk);
655 : :
656 : 1 : return ret;
657 : 16 : }
|