多EIP下的UDP通信异常分析

news/2024/5/18 15:59:39 标签: udp, 网络, 网络协议

背景

SRE和程序在测试DDos多EIP防御方案的过程中,发现多EIP模式下, 监听的UDP端口连接会出现客户端访问异常。 表现为客户端发送一次数据后服务端这边主动断开了,或是客户端和服务端同时断开。

该问题会导致业务在多EIP方案下无法达到预期效果,无法进行自动切换EIP对外提供服务。

环境

  • 业务场景:对外的进程默认走udp协议通信,UDP失败后会尝试走TCP协议。
  • 监听方式:0.0.0.0:端口。
  • 防火墙:对外提供的端口全开放。
  • 网络:云(单网卡多EIP)、物理机(多网卡/IP)。

问题定位

抓包发现通信异常的时候,数据包中间会有一个icmp数据包,而我们并没有使用icmp相关协议,并且是icmp unreachable提示。


$tcpdump -nvv -i any |grep 128.1.208.1 02

tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 2621 44 bytes

128.1.208.102.44731 > 128.1.208.149.3000: [udp sum ok] UDP, length 2

13.250.175.90.53 > 128.1.208.30.59236: [udp sum ok] 36073 q: A? ******. (148)

128.1.208.102.44731 > 128.1.208.149.3000: [udp sum ok] UDP, length 2

128.1.208.149 > 128.1.208.102: ICMP 128.1.208.149 udp port 3000 unreachable, length 38

128.1.208.102.44731 > 128.1.208.149.3000: [udp sum ok] UDP, length 2

当服务器创建 UDP socket 时,它可以把其中一个主机本地 IP 地址(包括广播地址)指定为 socket 的本 地 IP 地址。那么,只有当 UDP 包的目的 IP 地址与指定的地址相匹配时,该包才能被送到创建该 UPD socket 的业务层。否则,内核将返回一个 ICMP 端口不可达差错,而服务器(业务层)永远看不到该数 据报。

如果存在一个通配的 IP 地址,那么就隐含了一种优先级关系。如果为 UDP socket 指定了特定 IP 地址,那 么在匹配目的地址时,始终优先匹配该 IP 地址。只有在匹配不成功时才使用通配 地址进行匹配。

经常可以看到远端 IP 地址和远端端口号都显示为 .(或 0.0.0.0:*),其意思是该 socket 将接受来自任何 IP 地址和任何端口号的 UDP 数据报。大多数系统允许 UDP socket 对远端地址进行限制,以令其只能接收 来自特定 IP 地址和端口号的 UDP 数据报。

在伯克利派生系统中存在如下副作用:如果在指定远端地址(IP 和 PORT)时没有选择本地地址,那么内 核将自动选择本地地址。其值就成为“选择到达远端 IP 地址路由时”用于做路由判定的 IP 地址。

问题复现

服务端

import socket

ADDR = ('0.0.0.0', 12345) BUFSIZ = 65535

udpSerSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) udpSerSock.bind(ADDR)

while True:

print 'waiting for connection...'

data, addr = udpSerSock.recvfrom(BUFSIZ) udpSerSock.sendto(data, addr)

print '...recevied from {0}: {1}'.format(addr, data)

udpSerSock.close()

客户端

 

结论

在多IP且UDP的场景下, 如果使用了bind 0.0.0.0 这种方式, 操作系统会自动选择数据包回复的源地址, 默认 为默认路由对应接口的主IP。

解决方案

方案1:

更新服务端逻辑, 对进来的数据包进行目的地址判断, 使用正确的目的地做为发送数据的源地址, 避免系统自动选择出错(socket中的recvmsg). 

但是该方式改动较大、这个因为我们用的是boost的asio库,asio库不支持获取和修改IP_PKTINFO信息。

方案2

代码层实现分别bind 所有外网ip地址,达到和bind 0.0.0.0一样的效果。

该方式相比原方式改动最小。


http://www.niftyadmin.cn/n/459639.html

相关文章

使用npm安装pnpm包管理器

使用npm安装pnpm包管理器 一、安装 使用 npm install pnpm -g 命令安装pnpm npm install pnpm -g安装完成之后,使用pnpm -v命令查询是否成功安装,出现版本号即可 二、设置源 1.先查看源是否为淘宝的源 pnpm config get registry 2.设置源命令 pn…

【C++】内存管理、new和delete操作类型、operator new和operator delete函数、new和delete的实现原理

文章目录 1.C/C内存管理2.C语言的内存管理方式3.C内存管理方式3.1 new和delete操作内置类型3.2 new和delete操作自定义类型 4.operator new与operator delete函数5.new和delete的实现原理5.1内置类型5.2 自定义类型 1.C/C内存管理 在C/C中,内存管理是程序员负责管理…

【青书学堂】作业-计算机应用基础(高起专)

【青书学堂】作业-计算机应用基础(高起专) 第1题 单选题 在Word的编辑状态,按先后顺序依次打开了d1.doC、d2.doC、d3.doC、d4.doc 4个文档,当前的活动窗口的文档名为____。。 选项: A:d1.doc B:d2.doc C:d4.doc D:d3.doc 答案:C 第2题 单选题 在Excel中,保存工作簿时屏…

k8s控制器之DaemonSet--第二弹创建DaemonSet

YAML 示例 下面是 DaemonSet 的 YAML 文件示例 daemonset.yaml。该例子中的 DaemonSet 运行了一个 fluentd-elasticsearch 的 docker 镜像: apiVersion: apps/v1 kind: DaemonSet metadata:name: fluentd-elasticsearchnamespace: kube-systemlabels:k8s-app: flu…

node.js安装及配置教程(win11)

node.js安装及配置教程(win11) 一、下载二、安装三、环境配置 一、下载 官网下载:点击下载 根据自己电脑的位数选择对应的版本即可 网盘下载:点击下载 二、安装 下载完成后,双击运行程序,点击next 勾…

实战:NPMYARN构建工具实践-2023.6.22(测试成功)

实战:NPM&YARN构建工具实践-2023.6.22(测试成功) 目录 推荐文章 https://www.yuque.com/xyy-onlyone/aevhhf?# 《玩转Typora》 实验环境 gitlab/gitlab-ce:15.0.3-ce.0 jenkins/jenkins:2.346.3-2-lts-jdk11 openjdk 11.0.18 [rootDevops6 ~]#npm -v 6.14.12…

MATLAB算法实战应用案例精讲-【自动驾驶】自动驾驶中的自动泊车功能

目录 前言 什么是“自动泊车”? 有什么用? 有什么优点? 发展历程

python 异步 I/O

如果你想了解异步编程,那么必然会涉及出许多相关概念。 堵塞/非堵塞同步/异步多进程/多线程/协程 为什么我要学习这个话,因为我想搞懂异步框架和异步接口的调用。所以,我的学习路线是这样的: 1.python异步编程 2.python Web异步…