Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2001 Daniel Hartmeier
3 : : * Copyright (c) 2002 - 2008 Henning Brauer
4 : : * Copyright (c) 2012 Gleb Smirnoff <glebius@FreeBSD.org>
5 : : * Copyright (c) 2015, 2016 Nicira, Inc.
6 : : * All rights reserved.
7 : : *
8 : : * Redistribution and use in source and binary forms, with or without
9 : : * modification, are permitted provided that the following conditions
10 : : * are met:
11 : : *
12 : : * - Redistributions of source code must retain the above copyright
13 : : * notice, this list of conditions and the following disclaimer.
14 : : * - Redistributions in binary form must reproduce the above
15 : : * copyright notice, this list of conditions and the following
16 : : * disclaimer in the documentation and/or other materials provided
17 : : * with the distribution.
18 : : *
19 : : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 : : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 : : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 : : * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 : : * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 : : * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 : : * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 : : * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 : : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 : : * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 : : * POSSIBILITY OF SUCH DAMAGE.
31 : : *
32 : : * Effort sponsored in part by the Defense Advanced Research Projects
33 : : * Agency (DARPA) and Air Force Research Laboratory, Air Force
34 : : * Materiel Command, USAF, under agreement number F30602-01-2-0537.
35 : : *
36 : : * $OpenBSD: pf.c,v 1.634 2009/02/27 12:37:45 henning Exp $
37 : : */
38 : :
39 : : #include <config.h>
40 : :
41 : : #include "conntrack-private.h"
42 : : #include "ct-dpif.h"
43 : : #include "dp-packet.h"
44 : : #include "util.h"
45 : :
46 : : struct tcp_peer {
47 : : enum ct_dpif_tcp_state state;
48 : : uint32_t seqlo; /* Max sequence number sent */
49 : : uint32_t seqhi; /* Max the other end ACKd + win */
50 : : uint16_t max_win; /* largest window (pre scaling) */
51 : : uint8_t wscale; /* window scaling factor */
52 : : };
53 : :
54 : : struct conn_tcp {
55 : : struct conn up;
56 : : struct tcp_peer peer[2];
57 : : };
58 : :
59 : : enum {
60 : : TCPOPT_EOL,
61 : : TCPOPT_NOP,
62 : : TCPOPT_WINDOW = 3,
63 : : };
64 : :
65 : : /* TCP sequence numbers are 32 bit integers operated
66 : : * on with modular arithmetic. These macros can be
67 : : * used to compare such integers. */
68 : : #define SEQ_LT(a,b) INT_MOD_LT(a, b)
69 : : #define SEQ_LEQ(a,b) INT_MOD_LEQ(a, b)
70 : : #define SEQ_GT(a,b) INT_MOD_GT(a, b)
71 : : #define SEQ_GEQ(a,b) INT_MOD_GEQ(a, b)
72 : :
73 : : #define SEQ_MIN(a, b) INT_MOD_MIN(a, b)
74 : : #define SEQ_MAX(a, b) INT_MOD_MAX(a, b)
75 : :
76 : : static struct conn_tcp*
77 : 492 : conn_tcp_cast(const struct conn* conn)
78 : : {
79 : 492 : return CONTAINER_OF(conn, struct conn_tcp, up);
80 : : }
81 : :
82 : : /* pf does this in in pf_normalize_tcp(), and it is called only if scrub
83 : : * is enabled. We're not scrubbing, but this check seems reasonable. */
84 : : static bool
85 : 544 : tcp_invalid_flags(uint16_t flags)
86 : : {
87 : :
88 [ + + ]: 544 : if (flags & TCP_SYN) {
89 [ + - ][ - + ]: 136 : if (flags & TCP_RST || flags & TCP_FIN) {
90 : 0 : return true;
91 : : }
92 : : } else {
93 : : /* Illegal packet */
94 [ - + ]: 408 : if (!(flags & (TCP_ACK|TCP_RST))) {
95 : 0 : return true;
96 : : }
97 : : }
98 : :
99 [ + + ]: 544 : if (!(flags & TCP_ACK)) {
100 : : /* These flags are only valid if ACK is set */
101 [ + - ][ + - ]: 82 : if ((flags & TCP_FIN) || (flags & TCP_PSH) || (flags & TCP_URG)) {
[ - + ]
102 : 0 : return true;
103 : : }
104 : : }
105 : :
106 : 544 : return false;
107 : : }
108 : :
109 : : #define TCP_MAX_WSCALE 14
110 : : #define CT_WSCALE_FLAG 0x80
111 : : #define CT_WSCALE_UNKNOWN 0x40
112 : : #define CT_WSCALE_MASK 0xf
113 : :
114 : : static uint8_t
115 : 86 : tcp_get_wscale(const struct tcp_header *tcp)
116 : : {
117 : 86 : int len = TCP_OFFSET(tcp->tcp_ctl) * 4 - sizeof *tcp;
118 : 86 : const uint8_t *opt = (const uint8_t *)(tcp + 1);
119 : 86 : uint8_t wscale = 0;
120 : : uint8_t optlen;
121 : :
122 [ + + ]: 508 : while (len >= 3) {
123 [ - + + + ]: 422 : switch (*opt) {
124 : : case TCPOPT_EOL:
125 : 0 : return wscale;
126 : : case TCPOPT_NOP:
127 : 84 : opt++;
128 : 84 : len--;
129 : 84 : break;
130 : : case TCPOPT_WINDOW:
131 : 84 : wscale = MIN(opt[2], TCP_MAX_WSCALE);
132 : 84 : wscale |= CT_WSCALE_FLAG;
133 : : /* fall through */
134 : : default:
135 : 338 : optlen = opt[1];
136 [ - + ]: 338 : if (optlen < 2) {
137 : 0 : optlen = 2;
138 : : }
139 : 338 : len -= optlen;
140 : 338 : opt += optlen;
141 : : }
142 : : }
143 : :
144 : 86 : return wscale;
145 : : }
146 : :
147 : : static uint32_t
148 : 504 : tcp_payload_length(struct dp_packet *pkt)
149 : : {
150 : 1008 : return (char *) dp_packet_tail(pkt) - dp_packet_l2_pad_size(pkt)
151 : 504 : - (char *) dp_packet_get_tcp_payload(pkt);
152 : : }
153 : :
154 : : static enum ct_update_res
155 : 446 : tcp_conn_update(struct conn *conn_, struct conntrack_bucket *ctb,
156 : : struct dp_packet *pkt, bool reply, long long now)
157 : : {
158 : 446 : struct conn_tcp *conn = conn_tcp_cast(conn_);
159 : 446 : struct tcp_header *tcp = dp_packet_l4(pkt);
160 : : /* The peer that sent 'pkt' */
161 : 446 : struct tcp_peer *src = &conn->peer[reply ? 1 : 0];
162 : : /* The peer that should receive 'pkt' */
163 [ + + ]: 446 : struct tcp_peer *dst = &conn->peer[reply ? 0 : 1];
164 : 446 : uint8_t sws = 0, dws = 0;
165 : 446 : uint16_t tcp_flags = TCP_FLAGS(tcp->tcp_ctl);
166 : :
167 : 446 : uint16_t win = ntohs(tcp->tcp_winsz);
168 : : uint32_t ack, end, seq, orig_seq;
169 : 446 : uint32_t p_len = tcp_payload_length(pkt);
170 : : int ackskew;
171 : :
172 [ - + ]: 446 : if (tcp_invalid_flags(tcp_flags)) {
173 : 0 : return CT_UPDATE_INVALID;
174 : : }
175 : :
176 [ + + ]: 446 : if (((tcp_flags & (TCP_SYN | TCP_ACK)) == TCP_SYN)
177 [ + + ]: 2 : && dst->state >= CT_DPIF_TCPS_FIN_WAIT_2
178 [ + - ]: 1 : && src->state >= CT_DPIF_TCPS_FIN_WAIT_2) {
179 : 1 : src->state = dst->state = CT_DPIF_TCPS_CLOSED;
180 : 1 : return CT_UPDATE_NEW;
181 : : }
182 : :
183 [ + + ]: 445 : if (src->wscale & CT_WSCALE_FLAG
184 [ + + ]: 366 : && dst->wscale & CT_WSCALE_FLAG
185 [ + + ]: 345 : && !(tcp_flags & TCP_SYN)) {
186 : :
187 : 327 : sws = src->wscale & CT_WSCALE_MASK;
188 : 327 : dws = dst->wscale & CT_WSCALE_MASK;
189 : :
190 [ + + ]: 118 : } else if (src->wscale & CT_WSCALE_UNKNOWN
191 [ + - ]: 10 : && dst->wscale & CT_WSCALE_UNKNOWN
192 [ + - ]: 10 : && !(tcp_flags & TCP_SYN)) {
193 : :
194 : 10 : sws = TCP_MAX_WSCALE;
195 : 10 : dws = TCP_MAX_WSCALE;
196 : : }
197 : :
198 : : /*
199 : : * Sequence tracking algorithm from Guido van Rooij's paper:
200 : : * http://www.madison-gurkha.com/publications/tcp_filtering/
201 : : * tcp_filtering.ps
202 : : */
203 : :
204 : 445 : orig_seq = seq = ntohl(get_16aligned_be32(&tcp->tcp_seq));
205 [ + + ]: 445 : if (src->state < CT_DPIF_TCPS_SYN_SENT) {
206 : : /* First packet from this end. Set its state */
207 : :
208 : 55 : ack = ntohl(get_16aligned_be32(&tcp->tcp_ack));
209 : :
210 : 55 : end = seq + p_len;
211 [ + + ]: 55 : if (tcp_flags & TCP_SYN) {
212 : 31 : end++;
213 [ + + ]: 31 : if (dst->wscale & CT_WSCALE_FLAG) {
214 : 29 : src->wscale = tcp_get_wscale(tcp);
215 [ + - ]: 29 : if (src->wscale & CT_WSCALE_FLAG) {
216 : : /* Remove scale factor from initial window */
217 : 29 : sws = src->wscale & CT_WSCALE_MASK;
218 : 29 : win = DIV_ROUND_UP((uint32_t) win, 1 << sws);
219 : 29 : dws = dst->wscale & CT_WSCALE_MASK;
220 : : } else {
221 : : /* fixup other window */
222 : 0 : dst->max_win <<= dst->wscale & CT_WSCALE_MASK;
223 : : /* in case of a retrans SYN|ACK */
224 : 0 : dst->wscale = 0;
225 : : }
226 : : }
227 : : }
228 [ - + ]: 55 : if (tcp_flags & TCP_FIN) {
229 : 0 : end++;
230 : : }
231 : :
232 : 55 : src->seqlo = seq;
233 : 55 : src->state = CT_DPIF_TCPS_SYN_SENT;
234 : : /*
235 : : * May need to slide the window (seqhi may have been set by
236 : : * the crappy stack check or if we picked up the connection
237 : : * after establishment)
238 : : */
239 [ - + ]: 55 : if (src->seqhi == 1
240 [ # # ]: 0 : || SEQ_GEQ(end + MAX(1, dst->max_win << dws), src->seqhi)) {
241 : 55 : src->seqhi = end + MAX(1, dst->max_win << dws);
242 : : }
243 [ + + ]: 55 : if (win > src->max_win) {
244 : 55 : src->max_win = win;
245 : : }
246 : :
247 : : } else {
248 : 390 : ack = ntohl(get_16aligned_be32(&tcp->tcp_ack));
249 : 390 : end = seq + p_len;
250 [ + + ]: 390 : if (tcp_flags & TCP_SYN) {
251 : 18 : end++;
252 : : }
253 [ + + ]: 390 : if (tcp_flags & TCP_FIN) {
254 : 49 : end++;
255 : : }
256 : : }
257 : :
258 [ + + ]: 445 : if ((tcp_flags & TCP_ACK) == 0) {
259 : : /* Let it pass through the ack skew check */
260 : 1 : ack = dst->seqlo;
261 [ - + ]: 444 : } else if ((ack == 0
262 [ # # ]: 0 : && (tcp_flags & (TCP_ACK|TCP_RST)) == (TCP_ACK|TCP_RST))
263 : : /* broken tcp stacks do not set ack */) {
264 : : /* Many stacks (ours included) will set the ACK number in an
265 : : * FIN|ACK if the SYN times out -- no sequence to ACK. */
266 : 0 : ack = dst->seqlo;
267 : : }
268 : :
269 [ + + ]: 445 : if (seq == end) {
270 : : /* Ease sequencing restrictions on no data packets */
271 : 220 : seq = src->seqlo;
272 : 220 : end = seq;
273 : : }
274 : :
275 : 445 : ackskew = dst->seqlo - ack;
276 : : #define MAXACKWINDOW (0xffff + 1500) /* 1500 is an arbitrary fudge factor */
277 [ + + ]: 445 : if (SEQ_GEQ(src->seqhi, end)
278 : : /* Last octet inside other's window space */
279 [ + - ]: 426 : && SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws))
280 : : /* Retrans: not more than one window back */
281 [ + + ]: 426 : && (ackskew >= -MAXACKWINDOW)
282 : : /* Acking not more than one reassembled fragment backwards */
283 [ + + ]: 425 : && (ackskew <= (MAXACKWINDOW << sws))
284 : : /* Acking not more than one window forward */
285 [ + + ][ - + ]: 423 : && ((tcp_flags & TCP_RST) == 0 || orig_seq == src->seqlo
286 [ # # ][ # # ]: 0 : || (orig_seq == src->seqlo + 1) || (orig_seq + 1 == src->seqlo))) {
287 : : /* Require an exact/+1 sequence match on resets when possible */
288 : :
289 : : /* update max window */
290 [ + + ]: 423 : if (src->max_win < win) {
291 : 49 : src->max_win = win;
292 : : }
293 : : /* synchronize sequencing */
294 [ + + ]: 423 : if (SEQ_GT(end, src->seqlo)) {
295 : 191 : src->seqlo = end;
296 : : }
297 : : /* slide the window of what the other end can send */
298 [ + + ]: 423 : if (SEQ_GEQ(ack + (win << sws), dst->seqhi)) {
299 : 381 : dst->seqhi = ack + MAX((win << sws), 1);
300 : : }
301 : :
302 : : /* update states */
303 [ + + ][ - + ]: 423 : if (tcp_flags & TCP_SYN && src->state < CT_DPIF_TCPS_SYN_SENT) {
304 : 0 : src->state = CT_DPIF_TCPS_SYN_SENT;
305 : : }
306 [ + + ][ + + ]: 423 : if (tcp_flags & TCP_FIN && src->state < CT_DPIF_TCPS_CLOSING) {
307 : 44 : src->state = CT_DPIF_TCPS_CLOSING;
308 : : }
309 [ + + ]: 423 : if (tcp_flags & TCP_ACK) {
310 [ + + ]: 422 : if (dst->state == CT_DPIF_TCPS_SYN_SENT) {
311 : 77 : dst->state = CT_DPIF_TCPS_ESTABLISHED;
312 [ + + ]: 345 : } else if (dst->state == CT_DPIF_TCPS_CLOSING) {
313 : 44 : dst->state = CT_DPIF_TCPS_FIN_WAIT_2;
314 : : }
315 : : }
316 [ + + ]: 423 : if (tcp_flags & TCP_RST) {
317 : 24 : src->state = dst->state = CT_DPIF_TCPS_TIME_WAIT;
318 : : }
319 : :
320 [ + + ]: 846 : if (src->state >= CT_DPIF_TCPS_FIN_WAIT_2
321 [ + - ]: 47 : && dst->state >= CT_DPIF_TCPS_FIN_WAIT_2) {
322 : 47 : conn_update_expiration(ctb, &conn->up, CT_TM_TCP_CLOSED, now);
323 [ + + ]: 376 : } else if (src->state >= CT_DPIF_TCPS_CLOSING
324 [ + + ]: 47 : && dst->state >= CT_DPIF_TCPS_CLOSING) {
325 : 24 : conn_update_expiration(ctb, &conn->up, CT_TM_TCP_FIN_WAIT, now);
326 [ + + ]: 352 : } else if (src->state < CT_DPIF_TCPS_ESTABLISHED
327 [ + + ]: 303 : || dst->state < CT_DPIF_TCPS_ESTABLISHED) {
328 : 50 : conn_update_expiration(ctb, &conn->up, CT_TM_TCP_OPENING, now);
329 [ + + ]: 302 : } else if (src->state >= CT_DPIF_TCPS_CLOSING
330 [ + + ]: 279 : || dst->state >= CT_DPIF_TCPS_CLOSING) {
331 : 37 : conn_update_expiration(ctb, &conn->up, CT_TM_TCP_CLOSING, now);
332 : : } else {
333 : 265 : conn_update_expiration(ctb, &conn->up, CT_TM_TCP_ESTABLISHED, now);
334 : : }
335 [ - + ]: 22 : } else if ((dst->state < CT_DPIF_TCPS_SYN_SENT
336 [ # # ]: 0 : || dst->state >= CT_DPIF_TCPS_FIN_WAIT_2
337 [ # # ]: 0 : || src->state >= CT_DPIF_TCPS_FIN_WAIT_2)
338 [ + - ]: 22 : && SEQ_GEQ(src->seqhi + MAXACKWINDOW, end)
339 : : /* Within a window forward of the originating packet */
340 [ + - ]: 22 : && SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW)) {
341 : : /* Within a window backward of the originating packet */
342 : :
343 : : /*
344 : : * This currently handles three situations:
345 : : * 1) Stupid stacks will shotgun SYNs before their peer
346 : : * replies.
347 : : * 2) When PF catches an already established stream (the
348 : : * firewall rebooted, the state table was flushed, routes
349 : : * changed...)
350 : : * 3) Packets get funky immediately after the connection
351 : : * closes (this should catch Solaris spurious ACK|FINs
352 : : * that web servers like to spew after a close)
353 : : *
354 : : * This must be a little more careful than the above code
355 : : * since packet floods will also be caught here. We don't
356 : : * update the TTL here to mitigate the damage of a packet
357 : : * flood and so the same code can handle awkward establishment
358 : : * and a loosened connection close.
359 : : * In the establishment case, a correct peer response will
360 : : * validate the connection, go through the normal state code
361 : : * and keep updating the state TTL.
362 : : */
363 : :
364 : : /* update max window */
365 [ + + ]: 22 : if (src->max_win < win) {
366 : 2 : src->max_win = win;
367 : : }
368 : : /* synchronize sequencing */
369 [ + + ]: 22 : if (SEQ_GT(end, src->seqlo)) {
370 : 5 : src->seqlo = end;
371 : : }
372 : : /* slide the window of what the other end can send */
373 [ + + ]: 22 : if (SEQ_GEQ(ack + (win << sws), dst->seqhi)) {
374 : 10 : dst->seqhi = ack + MAX((win << sws), 1);
375 : : }
376 : :
377 : : /*
378 : : * Cannot set dst->seqhi here since this could be a shotgunned
379 : : * SYN and not an already established connection.
380 : : */
381 : :
382 [ + + ][ + - ]: 22 : if (tcp_flags & TCP_FIN && src->state < CT_DPIF_TCPS_CLOSING) {
383 : 2 : src->state = CT_DPIF_TCPS_CLOSING;
384 : : }
385 : :
386 [ - + ]: 22 : if (tcp_flags & TCP_RST) {
387 : 0 : src->state = dst->state = CT_DPIF_TCPS_TIME_WAIT;
388 : : }
389 : : } else {
390 : 0 : return CT_UPDATE_INVALID;
391 : : }
392 : :
393 : 445 : return CT_UPDATE_VALID;
394 : : }
395 : :
396 : : static bool
397 : 98 : tcp_valid_new(struct dp_packet *pkt)
398 : : {
399 : 98 : struct tcp_header *tcp = dp_packet_l4(pkt);
400 : 98 : uint16_t tcp_flags = TCP_FLAGS(tcp->tcp_ctl);
401 : :
402 [ - + ]: 98 : if (tcp_invalid_flags(tcp_flags)) {
403 : 0 : return false;
404 : : }
405 : :
406 : : /* A syn+ack is not allowed to create a connection. We want to allow
407 : : * totally new connections (syn) or already established, not partially
408 : : * open (syn+ack). */
409 [ + + ][ + + ]: 98 : if ((tcp_flags & TCP_SYN) && (tcp_flags & TCP_ACK)) {
410 : 6 : return false;
411 : : }
412 : :
413 : 92 : return true;
414 : : }
415 : :
416 : : static struct conn *
417 : 58 : tcp_new_conn(struct conntrack_bucket *ctb, struct dp_packet *pkt,
418 : : long long now)
419 : : {
420 : 58 : struct conn_tcp* newconn = NULL;
421 : 58 : struct tcp_header *tcp = dp_packet_l4(pkt);
422 : : struct tcp_peer *src, *dst;
423 : 58 : uint16_t tcp_flags = TCP_FLAGS(tcp->tcp_ctl);
424 : :
425 : 58 : newconn = xzalloc(sizeof *newconn);
426 : :
427 : 58 : src = &newconn->peer[0];
428 : 58 : dst = &newconn->peer[1];
429 : :
430 : 58 : src->seqlo = ntohl(get_16aligned_be32(&tcp->tcp_seq));
431 : 58 : src->seqhi = src->seqlo + tcp_payload_length(pkt) + 1;
432 : :
433 [ + + ]: 58 : if (tcp_flags & TCP_SYN) {
434 : 57 : src->seqhi++;
435 : 57 : src->wscale = tcp_get_wscale(tcp);
436 : : } else {
437 : 1 : src->wscale = CT_WSCALE_UNKNOWN;
438 : 1 : dst->wscale = CT_WSCALE_UNKNOWN;
439 : : }
440 : 58 : src->max_win = MAX(ntohs(tcp->tcp_winsz), 1);
441 [ + + ]: 58 : if (src->wscale & CT_WSCALE_MASK) {
442 : : /* Remove scale factor from initial window */
443 : 55 : uint8_t sws = src->wscale & CT_WSCALE_MASK;
444 : 55 : src->max_win = DIV_ROUND_UP((uint32_t) src->max_win, 1 << sws);
445 : : }
446 [ - + ]: 58 : if (tcp_flags & TCP_FIN) {
447 : 0 : src->seqhi++;
448 : : }
449 : 58 : dst->seqhi = 1;
450 : 58 : dst->max_win = 1;
451 : 58 : src->state = CT_DPIF_TCPS_SYN_SENT;
452 : 58 : dst->state = CT_DPIF_TCPS_CLOSED;
453 : :
454 : 58 : conn_init_expiration(ctb, &newconn->up, CT_TM_TCP_FIRST_PACKET,
455 : : now);
456 : :
457 : 58 : return &newconn->up;
458 : : }
459 : :
460 : : static uint8_t
461 : 92 : tcp_peer_to_protoinfo_flags(const struct tcp_peer *peer)
462 : : {
463 : 92 : uint8_t res = 0;
464 : :
465 [ + + ]: 92 : if (peer->wscale & CT_WSCALE_FLAG) {
466 : 70 : res |= CT_DPIF_TCPF_WINDOW_SCALE;
467 : : }
468 : :
469 [ - + ]: 92 : if (peer->wscale & CT_WSCALE_UNKNOWN) {
470 : 0 : res |= CT_DPIF_TCPF_BE_LIBERAL;
471 : : }
472 : :
473 : 92 : return res;
474 : : }
475 : :
476 : : static void
477 : 46 : tcp_conn_get_protoinfo(const struct conn *conn_,
478 : : struct ct_dpif_protoinfo *protoinfo)
479 : : {
480 : 46 : const struct conn_tcp *conn = conn_tcp_cast(conn_);
481 : :
482 : 46 : protoinfo->proto = IPPROTO_TCP;
483 : 46 : protoinfo->tcp.state_orig = conn->peer[0].state;
484 : 46 : protoinfo->tcp.state_reply = conn->peer[1].state;
485 : :
486 : 46 : protoinfo->tcp.wscale_orig = conn->peer[0].wscale & CT_WSCALE_MASK;
487 : 46 : protoinfo->tcp.wscale_reply = conn->peer[1].wscale & CT_WSCALE_MASK;
488 : :
489 : 46 : protoinfo->tcp.flags_orig = tcp_peer_to_protoinfo_flags(&conn->peer[0]);
490 : 46 : protoinfo->tcp.flags_reply = tcp_peer_to_protoinfo_flags(&conn->peer[1]);
491 : 46 : }
492 : :
493 : : struct ct_l4_proto ct_proto_tcp = {
494 : : .new_conn = tcp_new_conn,
495 : : .valid_new = tcp_valid_new,
496 : : .conn_update = tcp_conn_update,
497 : : .conn_get_protoinfo = tcp_conn_get_protoinfo,
498 : : };
|