P4可编程网络综合实践报告

基于P4的智能网络平台

项目Gitee仓库链接:仓库链接

摘要:本报告介绍了如何利用P4(Programming Protocol-Independent Packet Processors)的数据平面可编程特性,在交换机上实现3层网络安全防御。通过协议和端口过滤、泛洪攻击检测、重流检测以及对以太网、IPv4、IPv6、TCP和UDP标头字段的决策能力,我们能够减少对第三方中间件的依赖,提供新的网络安全防御解决方案。

一、项目背景

随着互联网的快速发展和普及,网络安全问题日益突出。恶意攻击、数据泄露、网络病毒等安全威胁不断涌现,给个人、组织和企业的信息安全带来了巨大的风险。
传统的网络安全解决方案通常依赖于中间件或外部设备,例如防火墙、入侵检测系统和安全网关等。然而,这些解决方案存在一些限制和挑战。首先,它们往往需要额外的硬件设备和软件部署,增加了成本和复杂性。其次,它们往往是针对特定协议或应用程序的,难以适应不断变化的网络环境和攻击手段。此外,它们的配置和管理也需要专业的技术人员进行操作,对于一些中小型组织而言,缺乏足够的资源和经验。
在这样的背景下,P4(Programming Protocol-Independent Packet Processors)的出现提供了一种新的解决方案。P4是一种可编程的数据平面编程语言,允许用户自定义网络设备上的数据包处理逻辑。通过利用P4的数据平面可编程性,可以在交换机等网络设备上实现灵活、高效的网络安全防御策略,减少对第三方中间件的依赖,提供更加定制化和适应性强的安全防护能力。
基于P4的网络安全解决方案具备协议和端口过滤、泛洪攻击检测、重流检测以及对以太网、IPv4、IPv6、TCP、UDP等标头字段的决策能力。通过在交换机上实现这些功能,可以提供更加细粒度的安全策略和更高效的网络安全防护能力,减少潜在的安全风险和威胁。
本项目的目标就是利用P4的数据平面可编程特性,实现基于交换机的3层网络安全防御,为网络安全提供新的解决方案。通过开发和部署P4网络安全架构,我们可以在现有网络基础设施上提供更强大、灵活和高效的网络安全防护能力,保护网络中的数据和系统安全,降低网络安全风险的发生和影响。

二、项目内容

  • 协议和端口过滤:通过在交换机上使用P4语言定义流表,可以根据数据包的协议类型和端口号进行匹配和过滤,实现对特定协议和端口的访问控制。
  • 防止泛洪攻击:利用P4的可编程特性,可以设置在一定时间段内限制数据包的数量或字节数,防止泛洪攻击的发生。通过使用计数器和流表,可以对数据包进行计数和处理。
  • 重放攻击检测:使用P4语言编写逻辑来检测和防止重放攻击。在数据平面中,可以存储和比较数据包的时间戳和序列号,以便检测和拦截已经被重复发送的数据包。
  • 网络流量监测和分析:利用P4的流表和计数器功能,可以对网络流量进行实时监测和统计。通过收集和分析流量数据,可以检测异常流量模式和识别潜在的安全威胁。
  • 定制化安全策略:使用P4语言可以自定义和实现各种安全策略,例如基于用户身份的访问控制、数据包的深度检查和过滤、加密和解密等。这使得网络管理员可以根据具体的安全需求定制适合自己网络环境的安全策略。
  • 快速响应和部署:P4的可编程性使得网络安全功能可以直接在数据平面上实现,无需依赖第三方中间件或额外的网络设备。这提供了更快速的响应和部署能力,以应对不断变化的网络安全威胁。
    总之,P4的数据平面编程能力使得我们能够实现定制化、灵活和高效的网络安全解决方案,提供了新的解决方案来应对不断增长和演变的网络安全挑战。

三、项目方法与思路

1. 协议和端口过滤

目标:在交换机级别过滤非法或不符合策略的协议和端口,从而防止潜在的网络攻击和未授权访问。
方法:编写 P4 程序对入站和出站的数据包进行解析,检查数据包的协议类型(如 IPv4、IPv6、TCP、UDP)和端口号。基于预定义的安全策略,如允许的端口列表和协议类型,对不符合规则的数据包执行丢包或重定向操作。
在流表中添加规则来匹配和处理特定的协议和端口。
匹配具有特定目的MAC地址、源MAC地址、协议和端口的流量。
如果匹配成功,则执行drop动作,否则执行forward动作。
drop动作将丢弃匹配的流量,而forward动作将允许流量通过。

// 定义P4头部字段
header ethernet_t {
    // 定义以太网目的MAC地址和源MAC地址字段
    bit<48> dstAddr;
    bit<48> srcAddr;
}

header ipv4_t {
    // 定义IPv4头部字段
    bit<4> version;
    bit<4> ihl;
    bit<8> diffserv;
    bit<16> totalLen;
    bit<16> identification;
    bit<3> flags;
    bit<13> fragOffset;
    bit<8> ttl;
    bit<8> protocol;
    bit<16> hdrChecksum;
    bit<32> srcAddr;
    bit<32> dstAddr;
}

header tcp_t {
    // 定义TCP头部字段
    bit<16> srcPort;
    bit<16> dstPort;
    bit<32> seqNo;
    bit<32> ackNo;
    bit<4> dataOffset;
    bit<6> flags;
    bit<16> window;
    bit<16> checksum;
    bit<16> urgentPtr;
}

// 定义P4流表
table access_control {
    key = {
        ethernet.dstAddr : exact;
        ethernet.srcAddr : exact;
        ipv4.protocol : exact;
        tcp.srcPort : exact;
    }
    actions = { drop, forward }
    size = 1024;

    // 在流表中添加规则来匹配和处理特定的协议和端口
    // 在这个示例中,我们只匹配具有特定目的MAC地址、源MAC地址、协议和端口的流量
    // 您可以根据需要添加更多规则,以满足您的过滤需求
    // 如果匹配成功,则执行drop动作,否则执行forward动作
    // drop动作将丢弃匹配的流量,而forward动作将允许流量通过
    actions = {
        drop;
        forward;
    }
    default_action = forward;
}

// 定义P4控制器逻辑
control ingress {
    // 应用协议和端口过滤规则
    apply(access_control);
}

2. 泛洪攻击检测

目标:检测并防止短时间内的大量数据包传输,这通常是 DDoS 攻击的一种形式。
方法:使用 P4 的 register 和 meter 功能。通过 register 记录特定时间窗口内(如 30 秒)每个源 IP 地址发送的数据包数量,结合 meter 来测量数据流的速率。当数据包数量超过阈值(如 5 个包或 500 字节)时,采取相应措施,如丢弃额外的包或发出警报。
在流表中添加规则来检测泛洪攻击。
如果匹配到具有相同源MAC地址、协议和源端口的数据包,则将其计数器递增。
如果计数器的值超过阈值,则执行flood动作,否则执行allow动作。

header flood_detection_t {
    bit<32> srcAddr;
    bit<16> srcPort;
}

// 定义P4计数器
counter flood_counter {
    type : packets;
    size : 65536;
}

// 定义P4流表
table flood_detection {
    key = {
        ethernet.srcAddr : exact;
        ipv4.protocol : exact;
        udp.srcPort : exact;
    }
    actions = { flood, allow }
    size = 1024;

    // 在流表中添加规则来检测泛洪攻击
    // 如果匹配到具有相同源MAC地址、协议和源端口的数据包,则将其计数器递增
    // 如果计数器的值超过阈值,则执行flood动作,否则执行allow动作
    actions = {
        flood;
        allow;
    }
    default_action = allow;
}

// 定义P4控制器逻辑
control ingress {
    // 应用泛洪攻击检测规则
    apply(flood_detection);
    // 更新计数器的值
    flood_counter.apply();
}

3. 重流检测

目标:识别并处理网络中的重复数据流,这可能是网络故障或恶意行为的迹象。
方法:对流进行唯一标识,通常是基于源 IP、目的 IP、源端口、目的端口和协议类型的组合。在 P4 程序中使用 register 来存储和跟踪每个流的出现次数。当检测到相同的流标识符再次出现时,根据配置的策略执行特定的动作(如标记流、丢弃数据包或重定向)。
在流表中添加规则来检测重流。
如果匹配到具有相同源MAC地址、协议和源端口的数据包,则将其计数器递增。
如果计数器的值大于1,则执行detect动作,表示检测到重流;否则执行allow动作,表示允许数据包通过。

// 定义P4流表
table replay_detection {
    key = {
        ethernet.srcAddr : exact;
        ipv4.protocol : exact;
        udp.srcPort : exact;
    }
    actions = { detect, allow }
    size = 1024;

    // 在流表中添加规则来检测重流
    // 如果匹配到具有相同源MAC地址、协议和源端口的数据包,则将其计数器递增
    // 如果计数器的值大于1,则执行detect动作,表示检测到重流;否则执行allow动作,表示允许数据包通过
    actions = {
        detect;
        allow;
    }
    default_action = allow;
}

// 定义P4控制器逻辑
control ingress {
    // 应用重流检测规则
    apply(replay_detection);
    // 更新计数器的值
    replay_counter.apply();
}

4. 标签和决策制定

目标:为通过安全检查的流量打上标签,并根据这些标签决定数据包的后续处理。
方法:利用 P4 程序中的 metadata 字段来存储每个数据流的状态和分类信息。基于流的标签值(如“合法”、“可疑”、“非法”),在网络的后续节点上执行相应的策略决策,如允许通过、进行额外的检查或直接阻止。

header ethernet_t {
    bit<48> dstAddr;
    bit<48> srcAddr;
}

header ipv4_t {
    bit<4> version;
    bit<4> ihl;
    bit<8> diffserv;
    bit<16> totalLen;
    bit<32> srcAddr;
    bit<32> dstAddr;
}

header vlan_t {
    bit<12> vlanId;
}

table policy_decision {
    key = {
        ethernet.srcAddr : exact;
        vlan.vlanId : exact;
    }
    actions = { forward, drop }
    size = 1024;

    // 在流表中添加规则来进行决策制定
    // 如果匹配到特定的标签和源MAC地址,则执行forward动作,否则执行drop动作
    actions = {
        forward;
        drop;
    }
    default_action = drop;
}

control ingress {
    // 应用决策制定规则
    apply(policy_decision);
}

5.控制平面与数据平面的交互

通过 SSH 连接到远程主机,并执行一系列命令的功能,包括编译和运行 P4 程序、发送数据包、接收数据包,并通过 SFTP 下载生成的日志文件:

  1. 连接到远程主机:使用paramiko模块的SSHClient类建立SSH连接,并设置主机的密钥策略。

  2. 创建SSH通道:通过invoke_shell方法创建四个通道channel1channel2channel3channel4,用于执行命令和接收输出。

  3. 发送命令:使用channel1.send方法发送一系列命令,包括切换到指定目录、执行lsmake stopmake等命令。

  4. 等待一段时间:使用time.sleep方法等待10秒,确保命令执行完成。

  5. 发送其他命令:使用channel2.send方法发送命令,切换到指定目录并执行mycontroller.py脚本。

  6. 发送更多命令:使用channel3.send方法发送命令,切换到指定目录并执行send.py脚本,其中hostnum是作为参数传递的。

  7. 发送更多命令:使用channel4.send方法发送命令,切换到指定目录并以sudo权限执行receive.py脚本。

  8. 循环等待并下载文件:使用循环和time.sleep方法等待一定时间,然后调用sftp_down_file函数下载远程主机上的文件到本地。

  9. 接收输出:使用channel4.recv_readychannel4.recv方法接收并解码通道4的输出,将结果存储在res变量中。

  10. 关闭SSH连接:使用ssh_client.close方法关闭SSH连接。

  11. 返回结果:返回res变量,即脚本执行的输出。

import time
import paramiko

def connect_and_work(host, num):
    ssh_client = paramiko.SSHClient()
    ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    ssh_client.connect('192.168.238.132', username='p4', password='p4')

    channel1 = ssh_client.invoke_shell()
    channel2 = ssh_client.invoke_shell()
    channel3 = ssh_client.invoke_shell()
    channel4 = ssh_client.invoke_shell()

    cmd1 = 'cd tutorials/exercises/final/ \n ls \n make stop \n make \n'
    channel1.send(cmd1.encode('utf-8'))

    time.sleep(10)

    cmd2 = 'cd tutorials/exercises/final/ \n ./mycontroller.py\n'
    channel2.send(cmd2.encode('utf-8'))
    time.sleep(1)
    print('init success')

    cmd3 = 'cd tutorials/exercises/final/ \n mx h1 \n ./send.py ' + host + ' ' + num + '\n'
    channel3.send(cmd3.encode('utf-8'))

    cmd4 = 'cd tutorials/exercises/final/ \n mx h1 \n sudo ./receive.py \n'
    channel4.send(cmd4.encode('utf-8'))
    # time.sleep(int(num))
    for i in range(0, int(num)):
        time.sleep(1)
        host = '192.168.238.132'
        user = 'p4'
        password = 'p4'

        server_path = '/home/p4/tutorials/exercises/final/log.txt'
        local_path = "D:/TempSdnPlus/temp.txt"
        res = sftp_down_file(host, user, password, server_path, local_path)
        # if res is True:
  
    res = ''
    while channel4.recv_ready():
        res += channel4.recv(1024).decode('utf-8')

    print(res)
    ssh_client.close()
    return res

def sftp_down_file(host,user,password,server_path, local_path,timeout=10):
    try:
        t = paramiko.Transport((host,22))
        t.banner_timeout = timeout
        t.connect(username=user,password=password)
        sftp = paramiko.SFTPClient.from_transport(t)
        sftp.get(server_path, local_path)
        t.close()
        return True
    except Exception as e:
        print(e)
        return False

6.数据包信息提取

解析一个包含特定格式信息的字符串,并提取出所需的信息:
具体功能如下:

  1. 将输入的字符串 info_str 按换行符分割成列表 temp
  2. 创建空列表 s,用于存储处理后的字符串。
  3. 遍历 temp 列表中从索引 6 开始的元素(排除前面几行不需要的信息)。
  4. 将非空的元素拼接成字符串 temp_s,并添加分隔符 ‘&’。
  5. 如果遇到空行,将 temp_s 加入列表 s 中,并重置 temp_s 为空字符串。
  6. 创建空列表 info1info2info3,分别用于存储不同类型的信息。
  7. 使用正则表达式提取包含元组和数字的信息。
    • 对于 s[0],匹配括号内的元组和冒号后的数字。将元组拆分为列表,并去除单引号,存储在 info1 中。
  8. 遍历列表 s,使用正则表达式匹配包含特定格式的信息并提取。
    • 对于 Received from 开头的信息,提取出括号内的元组,并存储在 info2 中。
    • 对于形如 Switch X - Port Y: Z Mbps 格式的信息,提取出交换机和端口号以及对应的速率,并存储在 info3 中。
  9. 将提取的信息存储在字典 info 中,使用键 'info1''info2''info3' 分别存储对应的信息列表。
  10. 返回字典 info

通过从输入的字符串中解析出特定格式的信息,并将其组织成结构化的数据,方便后续的处理和分析。

import re

def getinfo(info_str):
    temp = info_str.split('\n')
    s = []

    temp_s = '&'
    for i in range(6, len(temp)):
        if temp[i] == '':
            continue

        # print(temp[i])
        temp_s += '&' + temp[i]
        if i + 1 < len(temp) and temp[i + 1] == '':
            s.append(temp_s)
            temp_s = ''

    info1 = []
    info2 = []
    info3 = []

    # 提取元组和数字
    match = re.search(r"\((.*?)\)(.*?):\s*(\d+)", s[0])
    if match:
        # 解析元组
        arr = match.group(1).split(", ")
        arr = [x.strip("'") for x in arr]

        temp_info = {}
        temp_info['s1'] = arr[0]
        temp_info['s2'] = arr[1]
        temp_info['s3'] = arr[2]
        info1.append(temp_info)

    for i in s:
        pattern = r"Received from \('.*?', '.*?', \d+, \d+, \d+\) total: \d+"
        result = re.findall(pattern, i)
        if result:
            info2.append({'s1': result[0]})

    for i in s:
        pattern = r"(Switch \d+ - Port \d+): (\d+\.\d+) Mbps"
        result = re.findall(pattern, i)
        if result:
            temp_info3 = []
            for j in result:
                temp_info3.append({j[0]: j[1]})
            info3.append(temp_info3)

    # info = [info1, info2, info3]
    info = {
        'info1': info1,
        'info2': info2,
        'info3': info3
    }
    return info

四、项目结果

1.预警详情

在这里插入图片描述

实现了向目的IP地址发包并展示拦截情况的功能
拦截记录(左侧表格):列出了具体的拦截记录,包括序号、来源IP地址、目的IP地址、协议号、被拦截时间等信息。
收包情况(右侧表格):展示了收包情况的详细信息,包括序号和具体的收包详细信息,如来源IP地址、目的IP地址、协议号、端口和时间窗口。

网络拓扑示意图:底部展示了一个简化的网络拓扑图,可能用于显示网络中各设备和交换机的连接情况。

2.流量统计图表

在这里插入图片描述

利用曲线图展示了不同交换机端口的流量统计信息。
不同颜色的曲线代表不同交换机端口的流量变化情况,例如,Switch 1 的 Port 1、Port 3、Port 4,Switch 2 的 Port 3,Switch 3 的 Port 1、Port 2 和 Switch 4 的 Port 1、Port 2 等。
图表中展示了各个端口在不同时间点的流量变化趋势,提供了网络流量的动态监控能力。

鼠标悬停在图表上的某个点时,会显示该时间点的详细流量信息。

提供了可视化大屏

在这里插入图片描述

拦截记录:
左侧表格列出了最近的拦截记录,包括序号、来源 IP 地址、目的 IP 地址、协议号和被拦截时间。
该功能用于记录和显示网络中被拦截的数据包信息,帮助用户了解网络中的潜在安全威胁。

流量统计:
中间部分显示了不同交换机端口的流量统计信息,以条形图展示。
每个条形图代表一个交换机端口的流量值,例如 Switch 1 - Port 1 的流量为 666.69,Switch 1 - Port 2 的流量为 390.17等。
通过条形图,用户可以直观地看到不同端口的流量负载情况,有助于流量管理和故障排查。

收包情况:
左下方显示了详细的收包记录,包括序号和具体的收包详细信息,例如来源 IP 地址、目的 IP 地址、协议号、端口和时间窗口等。
该功能用于记录和显示网络中接收到的数据包信息,帮助用户监控网络流量。
提示框内容包括具体的交换机端口以及该端口在对应时间点的流量值。

拓扑结构:
右侧显示了网络的拓扑结构图,展示了交换机和其他网络设备的连接情况。
通过拓扑图,用户可以直观地了解网络设备的布局和连接关系,便于进行网络管理和故障定位。

总结与展望

本次实验较为困难,因前期资料查询、组员联络等准备不足,导致原本想做的实验二最终无法实现,后转向制作实验一,实验中查询了很多github上的资料,如https://github.com/jafingerhut/p4-guide等,但我们仍对P4开发有很多理解不够到位的地方。
P4 语言的灵活性使得我们能够在交换机上实现复杂的网络安全功能,减少了对第三方中间件的依赖。实验中遇到的问题和解决办法也让我对网络编程和安全防御有了更深入的理解和认识。
最后,我们认为P4 技术在网络安全领域的应用前景广阔,未来我们会进一步优化代码性能,并探索更多应用场景,继续学习P4技术,为网络安全防御提供更加全面和高效的解决方案。

参考文献:

[1] Bosshart P, Daly D, Gibb G, et al. P4: Programming protocol-independent packet processors[J]. ACM SIGCOMM Computer Communication Review, 2014, 44(3): 87-95.
[2] Zhao Y, Liang D, Li C, et al. A Survey on OpenFlow-based Software-Defined Networks: A Security Perspective[J]. IEEE Communications Surveys & Tutorials, 2017, 19(4): 3030-3056.
[3] Vörös P, Kiss A. Security middleware programming using
P4[C]//International Conference on Human Aspects of Information Security, Privacy, and
Trust. Springer, Cham, 2016: 277-287.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值