Wireshark & Packetdrill | TCP 三次握手之 SYN/ACK MSS

admin 2024年1月29日20:53:28评论8 views字数 5639阅读18分47秒阅读模式

有时候坚持之后,便可得到你最想要的东西

实验目的

基于 packetdrill TCP 三次握手脚本,继续测试 SYN/ACK 中 TCP options  MSS 字段的由来,此次构造模拟的是服务器端场景。

基础脚本

# cat tcp_3hs_000.pkt // TCP 基础之三次握手0   socket(..., SOCK_STREAM, IPPROTO_TCP) = 3+0  setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0+0  bind(3, ..., ...) = 0+0  listen(3, 1) = 0+0  < S 0:0(0) win 10000 <mss 1460>+0  > S. 0:0(0) ack 1 <...>+0.01 < . 1:1(0) ack 1 win 10000+0 accept(3, ..., ...) = 4

SYN/ACK MSS

SYN/ACK 中 TCP options 的 MSS 实际上也是本地通告的 MSS,代码中是通过 tcp_make_synack 函数确定的,相关的代码流程简要说明如下:

tcp_v4_rcv   |--tcp_v4_do_rcv   |  |--tcp_rcv_state_process   |     |--tcp_v4_conn_request   |        |--tcp_conn_request   |           |--tcp_v4_send_synack   |              |--tcp_make_synack

tcp_v4_rcv 函数,根据 TCP_LISTEN 状态判断,调用 tcp_v4_do_rcv -> tcp_rcv_state_process 。

int tcp_v4_rcv(struct sk_buff *skb){...process:  ...  if (sk->sk_state == TCP_LISTEN) {    ret = tcp_v4_do_rcv(sk, skb);    goto put_and_return;  }...}int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb){...  if (tcp_rcv_state_process(sk, skb)) {    rsk = sk;    goto reset;  }  return 0;...}

tcp_rcv_state_process 函数,同样根据 TCP_LISTEN 判断,如果是 SYN,调用 tcp_v4_conn_request 函数。

int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb){...  case TCP_LISTEN:    ...    if (th->syn) {      if (th->fin)        goto discard;      ...      acceptable = icsk->icsk_af_ops->conn_request(sk, skb) >= 0;      ...    }...}

tcp_v4_conn_request 函数,实际返回调用的 tcp_conn_request 函数。

int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb){  /* Never answer to SYNs send to broadcast or multicast */  if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))    goto drop;  return tcp_conn_request(&tcp_request_sock_ops,        &tcp_request_sock_ipv4_ops, sk, skb);...}

tcp_conn_request -> tcp_v4_send_synack -> tcp_make_synack,mss 将通过目的路由取到的 MSS 值与通过 setsockopt 设置的值 user_mss 比较,采用较小的一个作为 mss。之后通过 tcp_synack_options 将 mss 赋值给 opts->mss,最终通过 tcp_options_write 写入 options。

int tcp_conn_request(struct request_sock_ops *rsk_ops,         const struct tcp_request_sock_ops *af_ops,         struct sock *sk, struct sk_buff *skb){...    af_ops->send_synack(sk, dst, &fl, req, &foc,            !want_cookie ? TCP_SYNACK_NORMAL :               TCP_SYNACK_COOKIE,            skb);...}
static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst,            struct flowi *fl,            struct request_sock *req,            struct tcp_fastopen_cookie *foc,            enum tcp_synack_type synack_type,            struct sk_buff *syn_skb){...  skb = tcp_make_synack(sk, dst, req, foc, synack_type, syn_skb);...}
struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,        struct request_sock *req,        struct tcp_fastopen_cookie *foc,        enum tcp_synack_type synack_type,        struct sk_buff *syn_skb){...  mss = tcp_mss_clamp(tp, dst_metric_advmss(dst));...  tcp_header_size = tcp_synack_options(sk, req, mss, skb, &opts, md5,               foc, synack_type,               syn_skb) + sizeof(*th);...  tcp_options_write((__be32 *)(th + 1), NULL, &opts);...}
static inline u16 tcp_mss_clamp(const struct tcp_sock *tp, u16 mss){  /* We use READ_ONCE() here because socket might not be locked.   * This happens for listeners.   */  u16 user_mss = READ_ONCE(tp->rx_opt.user_mss);  return (user_mss && user_mss < mss) ? user_mss : mss;}
static inline u32dst_metric_advmss(const struct dst_entry *dst){  u32 advmss = dst_metric_raw(dst, RTAX_ADVMSS);  if (!advmss)    advmss = dst->ops->default_advmss(dst);  return advmss;}

实验测试一

通过 setsockopt 选项 TCP_MAXSEG 指定 MSS 值 为 1000,则服务器端 advmss 值为 1000,snd_mss 也为 1000。

# cat tcp_3hs_options_mss_008.pkt +0  socket(..., SOCK_STREAM, IPPROTO_TCP) = 3+0  setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0+0  bind(3, ..., ...) = 0+0  listen(3, 1) = 0+.1 getsockopt(3, SOL_TCP, TCP_MAXSEG, [536], [4]) = 0+.1 setsockopt(3, SOL_TCP, TCP_MAXSEG, [1000], 4) = 0+0  < S 0:0(0) win 10000 <mss 1200>+0  > S. 0:0(0) ack 1 <...>+0.01 < . 1:1(0) ack 1 win 10000+0 accept(3, ..., ...) = 4+.1 getsockopt(4, SOL_TCP, TCP_MAXSEG, [1000], [4]) = 0+0 %{print (tcpi_advmss)}%+0 %{print (tcpi_snd_mss)}%# # packetdrill tcp_3hs_options_mss_008.pkt 10001000#

抓包结果可见 SYN MSS 1200(来自于 < mss 1200 自定义值),SYN/ACK MSS 1000(来自于 setsockopt 所设置的 TCP_MAXSEG 1000)

# tcpdump -i any -nn port 8080tcpdump: data link type LINUX_SLL2tcpdump: verbose output suppressed, use -v[v]... for full protocol decodelistening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes23:50:02.668189 tun0  In  IP 192.0.2.1.54997 > 192.168.119.16.8080: Flags [S], seq 0, win 10000, options [mss 1200], length 023:50:02.668223 tun0  Out IP 192.168.119.16.8080 > 192.0.2.1.54997: Flags [S.], seq 4217887737, ack 1, win 65000, options [mss 1000], length 023:50:02.678345 tun0  In  IP 192.0.2.1.54997 > 192.168.119.16.8080: Flags [.], ack 1, win 10000, length 023:50:02.802040 ?     Out IP 192.168.119.16.8080 > 192.0.2.1.54997: Flags [F.], seq 1, ack 1, win 65000, length 023:50:02.802064 ?     In  IP 192.0.2.1.54997 > 192.168.119.16.8080: Flags [R.], seq 1, ack 1, win 10000, length 0

实验测试二

继续 SYN/ACK MSS 测试,通过修改目的路由 MSS 值 为 1000,从而影响 advmss。

通过 packetdrill pkt 文件中修改 advmss 值为 1000,执行脚本后,tcpdump 捕获结果可以看到 SYN options [mss 1000...]

# cat tcp_3hs_options_mss_009.pkt `ip route change 192.0.2.0/24 dev tun0 advmss 1000`0  socket(..., SOCK_STREAM, IPPROTO_TCP) = 3+0  setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0+0  bind(3, ..., ...) = 0+0  listen(3, 1) = 0+0  < S 0:0(0) win 10000 <mss 1200>+0  > S. 0:0(0) ack 1 <...>+0.01  < . 1:1(0) ack 1 win 10000+0  accept(3, ..., ...) = 4## packetdrill tcp_3hs_options_mss_009.pkt  # # tcpdump -i any -nn port 8080tcpdump: data link type LINUX_SLL2tcpdump: verbose output suppressed, use -v[v]... for full protocol decodelistening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes23:50:05.556233 ?     In  IP 192.0.2.1.60891 > 192.168.125.150.8080: Flags [S], seq 0, win 10000, options [mss 1200], length 023:50:05.556260 ?     Out IP 192.168.125.150.8080 > 192.0.2.1.60891: Flags [S.], seq 4272403448, ack 1, win 65000, options [mss 1000], length 023:50:05.566372 ?     In  IP 192.0.2.1.60891 > 192.168.125.150.8080: Flags [.], ack 1, win 10000, length 023:50:05.566455 ?     Out IP 192.168.125.150.8080 > 192.0.2.1.60891: Flags [F.], seq 1, ack 1, win 65000, length 023:50:05.566467 ?     In  IP 192.0.2.1.60891 > 192.168.125.150.8080: Flags [R.], seq 1, ack 1, win 10000, length 0
Wireshark & Packetdrill | TCP 三次握手之 SYN/ACK MSS

往期推荐

1. Wireshark 提示和技巧 | 捕获点之 TCP 三次握手
2. Wireshark 提示和技巧 | a == ${a} 显示过滤宏
3. Wireshark TS | 防火墙空闲会话超时问题
4. Wireshark TS | HTTP 传输文件慢问题
5. 网络设备 MTU MSS Jumboframe 全解

后台回复「TT」获取 Wireshark 提示和技巧系列 合集
后台回复「TS」获取 Wireshark Troubleshooting 系列 合集
如需交流或加技术群,可后台直接留言,我会在第一时间回复,谢谢!
Wireshark & Packetdrill | TCP 三次握手之 SYN/ACK MSS

原文始发于微信公众号(Echo Reply):Wireshark & Packetdrill | TCP 三次握手之 SYN/ACK MSS

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年1月29日20:53:28
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Wireshark & Packetdrill | TCP 三次握手之 SYN/ACK MSShttps://cn-sec.com/archives/2440789.html

发表评论

匿名网友 填写信息